February 13, 2006
Matthew wrote:
> "nick" <nick.atamas@gmail.com> wrote in message That's fair. But I think they're likely to not want to waste their time here, and so will have an open mind to new idioms. That's likely to be of more use and less bother in the long run, I think.

You would hope that they would have an open mind and use the D features. But look at this quote:
>> What about someone who simply wants to maintain multiple references to a non-class type?  C interfacing might be the most common use, but it certainly isn't the only use.

Maybe I'm misreading that, but isn't he basically saying "let's use c-style pointers". That's coming from someone who has been on the D newsgroup for some time. It's a testament to how much people get used to doing things a certain way. That particular person comes from a strong C/C++ background if I am not mistaken.

My experience outside the D newsgroup shows this mentality to be true in general; it is human nature I guess.


Then there is the specific matter of the /in/ keyword being easily broken by a c-style pointer. There may be other high-level features that are compromised by low-level features. That has to be looked into.

> And now I fully follow your point, I agree that const would be perfect to your requirements.
Agreed, const would fix this particular problem. Even better, the semantics of /in/ can be modified so that it works more like const. However, I don't know if actual const parameters in D is what we need, because in/out/inout are a more explicit way of accomplishing the same idea. I realize that it's just a trade-off between the flexibility of const and the explicit nature of in/out


My rambling about C++'s const follow:
I've got beef with C++'s implementation of const. Allow me to explain.
In C++ const serves multiple purposes that are related but not quite the
same. Specifically, it can serve to signify that:
1. a function parameter is const e.g. 'void foo(const A &a)'
2. a method doesn't modify its object e.g. 'void foo() const'
3. a variable will never change e.g. const pi = 3.1415...; or const A a;

I think it's perfectly cool to use const for #3 (does D only allow this
for primitives?)

In case of #2, I don't think that it makes sense because in/out/inout is more elegant. It seems that even in low-level code, in/out/inout can replace const in most cases.

I am unsure about #1. It does cause a refactoring problem. On the other hand, D has a simple syntax, so a refactoring tool may be easy to implement. But then, maybe everything should be const by default and we should explicitly make things mutable.
February 13, 2006
I've read articles by Joel before, and while he's usually pretty good he can be off just as often.  It's not the king's word or anything.

Arrays can be passed using in and they can still change.  Only the array structure (length, pointer) cannot change.  There is no such guarantee for the data it points to (since both arrays point to the same place.)

I think the in keyword is very useful, if nothing else because of its semantic value.  But, even with it, something like this is still possible:

class A
{
    B b = null;
    int i = 1;
}

class B
{
    int j = 1;
}

int main()
{
    void test(in A a)
    {
        a.i = 6;
        a.b.j = 6;
    }

    A a = new A();
    a.b = new B();
    a.i = 5;
    a.b.j = 5;

    test(a);

    printf("i: %i, j: %i\n", a.i, a.b.j);

    return 0;
}

Run that and i and j will both be 6.  All that cannot happen is that a cannot be changed.  It really is not const.

As for the example you quoted, I'm afraid I am indeed guilty of a typo.  Anyway, for your enjoyment, here's a more complete example:

void surprise(in char[4] array)
{
    ubyte[] x = cast(ubyte[100]) array;
    x[99] = 1;
}

int main()
{
    char[4] char_array;
    ubyte[96] ubyte_array;

    surprise(char_array);

    foreach (ubyte u; ubyte_array)
    {
        if (u != 0)
            printf("1\n");
    }

    return 0;
}

You'll note, again, please, that I didn't use a single pointer.  Also, array bounds checking is enabled.  I'm doing everything great, except a bit of casting, since I know what it's doing behind the scenes.

This will print 1, even though ubyte_array was automatically initialized to 0 (one of the only things D does automatically to prevent bugs.) This means that I overwrote some other "innocent by-standard" variable.  Without even typing a single asterisk.

I didn't say they were "pointer bugs" or anything of the sort.  I said they were sloppy/stupid programming, and things that cannot be prevented by using "safe" code.

In other words: if someone doesn't know what they're doing, they shouldn't be doing it.  I don't see people arguing in court rooms that they're amateur drivers or anything inane like that, but yet it happens for programmers.  Driving is no simple thing, but people actually spend the time to master it.  It's not that different.

But if you can't drive - whether because you're blind, or simply haven't learned yet - you'd best get off the darn road.  Or at least be aware that you should avoid doing anything stupid.  If your amateur programmer friends can't figure this out they're not nearly as intelligent as you're making them out to be.

(Please note, of course, that everyone has to learn.  But that's what driver's ed is for, and what other things are for.  You just shouldn't be in production/on the road if you can't figure things out yet.)

-[Unknown]


> Pointer problems are notoriously difficult to track. Pointers are a
> feature that is not necessary in 90% of production code. Hey, Joel
> called them DANGEROUS. (I'm going to use that one a lot now.)
> 
> My example demonstrates a potential error that, if occurs in a library
> that you don't have source for, will cause you hours of grief. My
> example was carefully constructed. In it an object was passed in using
> the /in/ keyword. That should guarantee that my copy of the object
> doesn't change. If you are saying it is OK for it to change, then you
> are basically saying that the /in/ keyword is useless (well, not really
> useless but almost). I don't think that's cool.
> 
> Unknown W. Brackets wrote:
>> What's going to stop them from making other mistakes, unrelated to
>> pointers?  For example, the following:
>>
>> void surprise(in char[] array)
>> {
>>     ubyte[100] x = cast(ubyte[100]) array;
>>     array[99] = 1;
>> }
>>
>> This will compile fine, and uses zero pointers.  It's exactly the same
>> concept, too.
> No, it won't compile. Maybe I have a different version of dmd, but I get
> this:
> main.d(3): e2ir: cannot cast from char[] to ubyte[100]
> 
> Try it yourself.
> 
> The rest of these aren't really pointer bugs. So, if you want to try a
> slippery slope and argue that all of programming is unsafe, be my guest.
> It isn't particularly productive though. (Sorry, I am getting cranky;
> it's late.)
> 
> Here's another one:
>> void surprise(in int i)
>> {
>>     if (i == 0 || i > 30)
>>         return i;
>>     else
>>         return surprise(--i);
>> }
>>
>> Oops, what happens if i is below 0?  Oh, wait, here's another common
>> mistake I see:
>>
>> for (int i = 0; i != len; i++)
>> {
>>     ...
>> }
>>
>> What happens if len is negative?  I've seen this happen, a lot, in more
>> than a few different people's code.  They weren't stupid, you're right,
>> but it did happen.
>>
>> So do we mark != in fors as "unsafe"?  Recursion too?  And forget
>> casting, any casting is unsafe now as well?
>>
>> Seems to me like you're going to end up spending longer dealing with
>> their problems, if they think they can use pointers but really can't,
>> than you would just reviewing their darn code.
>>
>> Oh wait, it's only open source where you do that "code review" thing.
>> Otherwise it's considered a waste of time, except in huge corporations.
>>  Why bother when "unsafe" can just fix everything for you like magic?
>>
>> Valentine's day is coming up... good thing there are flowers, they just
>> fix everything too.  I can be a jerk and all I need are flowers, right?
>>  Magic.
>>
>> -[Unknown]
February 13, 2006
When I went into Computer Science, practically the first thing the teacher showed us was "cout".  Luckily, I already knew programming well enough to know that was stupid, and ended up teaching a large portion of the students in the class basic programming concepts.

When the first thing you see is a bad example, it's really hard to fix things.  Agreed, D has its flukes and its documentation is not perfect, but I haven't seen any code encouraging the abuse of pointers, references, for loops, casts, or asserts for that matter.

Most amateur programmers are copy-and-paste programmers, or are being taught by someone else.  In either case, they usually don't really 100% understand what they are doing, and a "danger use this instead" notice won't help them.

Consider, for example, if for always suggested that you use foreach instead.  You are guaranteed in bounds and you can't make as many mistakes, after all... right?  You know what would happen, right? People would do this:

int for_loop[1000];
foreach (int i, int ignore; for_loop)
   writefln(i);

Isn't that the better way?  No mistakes there... just a lot more memory usage.  Who cares about that anyway, right?  Computers are loaded these days.

I don't see any example where you removed anything from any spec. Everything seems to work as I expected in all the examples you've given.

There's really just one way to fix mistakes.  And it's not bandaids or notices.  And half the point of Joel's article, which you so carefully chose to ignore, was that learning to understand pointers is crucial to general understanding and principles.

-[Unknown]


> Unknown W. Brackets wrote:
>> Well, it's clearly not helping them, is it?  Most programmers may or may
>> not know what in the world they're doing, but most of the programmers I
>> want to hire or have work with me will.
>>
>> All of the features you listed are there to help people who are sensible
>> detect errors.  Lovely things they are, too.  But they don't just get
>> used, you have to use them.  If you don't, you're no better off than if
>> you didn't.
>>
>> Mistakes happen, but gross mistakes shouldn't.  If they do, the person
>> needs to go back and bake in training/school/less important projects for
>> a while.  No language can change this, however many keywords or flags it
>> adds.
>>
>> -[Unknown]
>>
>>
>>> Most programmers are amateurs; you're not going to change that.
> 
> That's an easy one. You can't do unsafe things without wrapping your
> code in the unsafe keyword. That's fairly easy to add, if you ask me.
> However, when that amateur gets the compiler error, he/she will look it
> up. Once they do, there will be a big notice "DANGER, USE THIS INSTEAD".
> 
> I work with a lot of EEs who only had one or two programming courses.
> They get a job mainly based on their hardware architecture knowledge.
> Now they have I have to work with them and write a hardware simulator.
> 
> Oh, I don't know if you realize this, but essentially removed
> /in/out/inout from the D spec with my example; please go read it.
> 
> If you think that people are going to use the language the RIGHT way
> when there is such a tempting wrong way, I suggest you look at C++ and
> its operator overloading.
February 13, 2006
All in does is effect the parameter in question.  In this case, said parameter is a pointer (reference, whatever you want to call it) to an instance of A.  You can change said instance all you like; you just cannot change the pointer.

Please read the documentation more carefully.

-[Unknown]


> Andrew Fedoniouk wrote:
>>> I will skip the "pointers are unsafe" rigmarole.
>>>
>>> Should D provide something analogous to the C# unsafe keyword?
>>
>> If "safe" means "managed" and
>>  "unsafe" means "unmanaged" then answer is no.
>> By definition as  D code is "unmanaged".
>>
>> To implement realy "safe" mode (whatever it means) you need
>> at least VM creating safe sandbox for you.
>>
>> Andrew. 
> 
> I didn't say I had a solution, I just said I have a problem. The
> "unsafe" thing is just some syntax that looked pretty cool in C#.
> 
> If c-style pointers are left the way they are now, you might as well not
> have in/out/inout parameters. To save you from reading the rest of the
> thread, here is an example:
> 
> CODE:
> -----
> 
> import std.stdio;
> 
> class A
> {
> 	private int data[];
> 	
> 	public this()
> 	{
> 		data.length = 10;
> 	}
> 	
> 	public void printSelf()
> 	{
> 		writefln("Data: ", this.data);
> 	}
> }
> 
> void surprise(in A a)
> {
> 	byte *ap = cast(byte *)(a);
> 	ap[9] = 5;	
> }
> 
> int main()
> {
> 	A a = new A();
> 	a.printSelf();
> 	surprise(a);
> 	a.printSelf();
> 	return 0;
> }
> 
> 
> OUTPUT:
> -------
> 
> Data before surprise: [0,0,0,0,0,0,0,0,0,0]
> Data after surprise:
> [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4287008,0,2004,216,1245184,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
> 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8855552,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
> 0,0,0,0,0,0,0,0,0,0,0,8855680,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8855808,
> <..SNIP..>
> 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
> 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
February 13, 2006
"nick" <nick.atamas@gmail.com> wrote in message news:dspgi4$1d03$1@digitaldaemon.com...
> Matthew wrote:
>> "nick" <nick.atamas@gmail.com> wrote in message
>> That's fair. But I think they're likely to not want to waste their time
>> here, and so will have an open mind to new idioms. That's likely to be of
>> more use and less bother in the long run, I think.
>
> You would hope that they would have an open mind and use the D features. But look at this quote:
>>> What about someone who simply wants to maintain multiple references to a non-class type?  C interfacing might be the most common use, but it certainly isn't the only use.
>
> Maybe I'm misreading that, but isn't he basically saying "let's use c-style pointers". That's coming from someone who has been on the D newsgroup for some time. It's a testament to how much people get used to doing things a certain way. That particular person comes from a strong C/C++ background if I am not mistaken.

Well, Sean's very experienced in both C++ and D, and I tend to pay attention when he's opining. (Sean's going to be one of the reviewers on my new book. <g>) However, that doesn't proof him from the same frailties and preconceptions as the rest of us.

> My experience outside the D newsgroup shows this mentality to be true in general; it is human nature I guess.

If your point is that pointers should not be part of any of the mainline idioms of D, much less the language/std-libs, then I agree. I don't know if it's still the case, but the associative arrays used to have use pointers as part of its semantics. Fingers crossed that's no longer the case.

> Then there is the specific matter of the /in/ keyword being easily broken by a c-style pointer. There may be other high-level features that are compromised by low-level features. That has to be looked into.

No argument with the call for taking another look.

>> And now I fully follow your point, I agree that const would be perfect to your requirements.
> Agreed, const would fix this particular problem. Even better, the semantics of /in/ can be modified so that it works more like const. However, I don't know if actual const parameters in D is what we need, because in/out/inout are a more explicit way of accomplishing the same idea. I realize that it's just a trade-off between the flexibility of const and the explicit nature of in/out

It wouldn't have to be exactly the same as C++ const, but it'd have to confer all the advantages.

> My rambling about C++'s const follow:
> I've got beef with C++'s implementation of const. Allow me to explain.
> In C++ const serves multiple purposes that are related but not quite the
> same. Specifically, it can serve to signify that:
> 1. a function parameter is const e.g. 'void foo(const A &a)'
> 2. a method doesn't modify its object e.g. 'void foo() const'
> 3. a variable will never change e.g. const pi = 3.1415...; or const A a;
>
> I think it's perfectly cool to use const for #3 (does D only allow this
> for primitives?)
>
> In case of #2, I don't think that it makes sense because in/out/inout is more elegant. It seems that even in low-level code, in/out/inout can replace const in most cases.
>
> I am unsure about #1. It does cause a refactoring problem. On the other hand, D has a simple syntax, so a refactoring tool may be easy to implement. But then, maybe everything should be const by default and we should explicitly make things mutable.

#1 and #2 are closely related, and that's an important feature of the keyword. I agree that mixing its name with the keyword for constants is a bad one - readonly would be much better - but C++ has a long and sorry history of reusing keywords inappropriately. What does typename mean? What does class mean? How are pre-/post- inc/decrement operators discriminated? How does one designate a pure virtual function? And so on. All hideous, to be sure.


February 13, 2006
"nick" <nick.atamas@gmail.com> wrote in message news:dsp8bc$143b$1@digitaldaemon.com...
> I must disagree. There are too many people to teach. In some cases it is a lot easier to modify a language than to teach everyone not to use a feature. This may be one of those cases. I think experts tend to forget that a language is there to help programmers develop software and to reduce chances of human error.

On the one hand, I agree with you. Often, when I show that feature X of D
will eliminate a certain common class of errors one gets with C++, the
response I get back is that "yes, but one can follow this procedural rigor
with C++ and not get that error." Well, sure, if everyone is a god-like
programmer.
But they aren't, and if you're an employer, you'll inevitably be hiring mere
mortal programmers, and if you work on a team, they'll be mere mortals too,
despite being a god oneself <g>.

On the other hand, having powerful (but dangerous) features are just too useful to ignore. How do we solve this? We can't. But we can try to mitigate it, and D does so by:

1) Trying to make the natural thing to do the right way to do it. D's arrays and reference objects are good examples of this.

2) Making practices that often lead to bugs be more visible in the code, so that code reviews can zero in on them, or even so that they're more greppable. Going from the C-style cast to requiring a 'cast' keyword is an example of this.

3) Finding attractive alternatives to common uses of unsafe practices - out and inout parameters are a good example here.

C# had a similar idea with the 'unsafe' keyword. It has some advantages - being keyword based, it can be flagged by the compiler if so desired, and it can be grepped for. It has one big disadvantage, though - it's just awful <g>. I find it grating to be forced to label code as "unsafe" when, as a programmer, I know it's perfectly safe. It's patronizing. It makes the language feel like it is not for professionals.

Although D eliminates maybe 90% of the need for explicit pointers, they're still needed here and there. I'd like to go that last 10%, but I don't think 'unsafe' is the right way to do it, even if its heart is in the right place.


February 13, 2006
Unknown W. Brackets wrote:
> Consider, for example, if for always suggested that you use foreach instead.  You are guaranteed in bounds and you can't make as many mistakes, after all... right?  You know what would happen, right? People would do this:
> 
> int for_loop[1000];
> foreach (int i, int ignore; for_loop)
>    writefln(i);
> 
> Isn't that the better way?  No mistakes there... just a lot more memory usage.  Who cares about that anyway, right?  Computers are loaded these days.
> 

Ok, I really don't see why foreach should/would use more memory? Or I didn't understand something?
February 13, 2006
Creating the array would use more memory.  Consider:

int for_loop[] = new int[some_undetermined_int];
...

That could use, right there, 5 megabytes.  It probably wouldn't, but it could.  Even so, what's the point of using the extra 4k from my initial example?

My meaning was that someone might create an array, and use it entirely and ONLY for the use of foreaching over it.  After that, the array, and its contents, would be ignored and not used.  Further, because delete is unsafe, it would not be deleted until the garbage collector picked it up.

Obviously this example is a bit out there, but I was trying to be illustrative.

-[Unknown]


> Unknown W. Brackets wrote:
>> Consider, for example, if for always suggested that you use foreach instead.  You are guaranteed in bounds and you can't make as many mistakes, after all... right?  You know what would happen, right? People would do this:
>>
>> int for_loop[1000];
>> foreach (int i, int ignore; for_loop)
>>    writefln(i);
>>
>> Isn't that the better way?  No mistakes there... just a lot more memory usage.  Who cares about that anyway, right?  Computers are loaded these days.
>>
> 
> Ok, I really don't see why foreach should/would use more memory? Or I didn't understand something?
February 13, 2006
In article <dspn17$1lbq$1@digitaldaemon.com>, Walter Bright says...
>
>
>3) Finding attractive alternatives to common uses of unsafe practices - out and inout parameters are a good example here.
I like the syntax of in, out and inout - it's very explicit. However, when it comes to objects, I am not sure sure the semantics are the best at the moment.

For example, given this code:
class A{ public int q;}
void surprise( in A a ){a.q = 5;}

a call to surprise(a) will change the value of 'a'. Is there no way to guarantee that the value of 'a' doesn't change in a function?

>C# had a similar idea with the 'unsafe' keyword. It has some advantages - being keyword based, it can be flagged by the compiler if so desired, and it can be grepped for. It has one big disadvantage, though - it's just awful <g>. I find it grating to be forced to label code as "unsafe" when, as a programmer, I know it's perfectly safe. It's patronizing. It makes the language feel like it is not for professionals.
Well, would it be ok to just change the keyword to 'raw' or maybe 'h4x0r_31337'. Then we can feel good about using it; I know I would. = )

>Although D eliminates maybe 90% of the need for explicit pointers, they're still needed here and there. I'd like to go that last 10%, but I don't think 'unsafe' is the right way to do it, even if its heart is in the right place.
I think that if we changed the semantics of /in/ or provided some equivalent of a 'const type*', that would help.


February 13, 2006
Matthew wrote:
> "nick" <nick.atamas@gmail.com> wrote in message news:dspgi4$1d03$1@digitaldaemon.com...
>> Matthew wrote:
>>> "nick" <nick.atamas@gmail.com> wrote in message
>>> That's fair. But I think they're likely to not want to waste their time
>>> here, and so will have an open mind to new idioms. That's likely to be of
>>> more use and less bother in the long run, I think.
>> You would hope that they would have an open mind and use the D features.
>> But look at this quote:
>>>> What about someone who simply wants to maintain multiple references to a non-class type?  C interfacing might be the most common use, but it certainly isn't the only use.
>> Maybe I'm misreading that, but isn't he basically saying "let's use
>> c-style pointers". That's coming from someone who has been on the D
>> newsgroup for some time. It's a testament to how much people get used to
>> doing things a certain way. That particular person comes from a strong
>> C/C++ background if I am not mistaken.
> 
> Well, Sean's very experienced in both C++ and D, and I tend to pay attention when he's opining. (Sean's going to be one of the reviewers on my new book. <g>) However, that doesn't proof him from the same frailties and preconceptions as the rest of us.

I was merely trying to point out that there are some situations where I might use a pointer in C/C++ that doesn't have a 'safe' D analog. However, it was somewhat of a weak position, as most of the examples could be refactored fairly easily to use classes to store the dynamically referenced data rather than using C-like pointers--the first example I thought of was the reference counter for shared pointers.


Sean