Community

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.

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]

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.

"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.

"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.

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?

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?

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.

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