March 04, 2009

Andrei Alexandrescu wrote:
> I suggested to Walter an idea he quite took to: offering the ability of disabling the default constructor. This is because at root any null pointer was a pointer created with its default constructor. The feature has some interesting subtleties to it but is nothing out of the ordinary and the code must be written anyway for typechecking invariant constructors.
> 
> That, together with the up-and-coming alias this feature, will allow the creation of the "perfect" NonNull!(T) type constructor (along with many other cool things). I empathize with those who think non-null should be the default, but probably that won't fly with Walter.
> 
> 
> Andrei

If Walter can get this working so that we can create NonNull as a wrapper struct that guarantees it will always be non-null, that'll be a big step forward.

Yes, I'd prefer it be the default, but better possible than not.  :)

  -- Daniel
March 04, 2009
On 2009-03-03 13:59:16 -0500, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> said:

> I suggested to Walter an idea he quite took to: offering the ability of disabling the default constructor. This is because at root any null pointer was a pointer created with its default constructor. The feature has some interesting subtleties to it but is nothing out of the ordinary and the code must be written anyway for typechecking invariant constructors.
> 
> That, together with the up-and-coming alias this feature, will allow the creation of the "perfect" NonNull!(T) type constructor (along with many other cool things). I empathize with those who think non-null should be the default, but probably that won't fly with Walter.

That'd be great, really.

But even then, NonNull!(T) will probably be to D what auto_ptr< T > is to C++: a very good idea with a very bad syntax only expert programmers use. C++ makes the safest pointer types the less known; please convince Walter we shouldn't repeat that error in D.


-- 
Michel Fortin
michel.fortin@michelf.com
http://michelf.com/

March 04, 2009
Daniel Keep wrote:
>> * Accessing arrays out-of-bounds
>> * Dereferencing null pointers
>> * Integer overflow
>> * Accessing uninitialized variables
>>
>> 50% of the bugs in Unreal can be traced to these problems!
> 
> Tim Sweeny isn't an amateur; he's responsible, at least in part, for one
> of the most commercially successful game engines ever.  I figure if even
> he has trouble with these things, it's worth trying to fix them.
> 
> Note that D already solves #1 and #4, LDC could give us #3... that just
> leaves #2.  :D

1 and 4 are pernicious, memory corrupting, hard to find problems. 2 is easy to find, does not corrupt memory. It isn't even in the same continent as 1 and 4 are.

3 is a problem, but fortunately it tends to be rare.
March 04, 2009
Jarrett Billingsley wrote:
> Exactly.  I thought one of the ideas behind D was to have "safe"
> defaults.  Yeah, I know, null references can't actually do damage to
> your computer because of virtual memory, but neither can concurrent
> access to shared data, or accessing uninitialized variables, but
> they're taken care of.

Those last two *are* unsafe, memory corrupting problems.
March 04, 2009

Walter Bright wrote:
> Daniel Keep wrote:
>>> * Accessing arrays out-of-bounds
>>> * Dereferencing null pointers
>>> * Integer overflow
>>> * Accessing uninitialized variables
>>>
>>> 50% of the bugs in Unreal can be traced to these problems!
>>
>> Tim Sweeny isn't an amateur; he's responsible, at least in part, for one of the most commercially successful game engines ever.  I figure if even he has trouble with these things, it's worth trying to fix them.
>>
>> Note that D already solves #1 and #4, LDC could give us #3... that just leaves #2.  :D
> 
> 1 and 4 are pernicious, memory corrupting, hard to find problems. 2 is easy to find, does not corrupt memory. It isn't even in the same continent as 1 and 4 are.
> 
> 3 is a problem, but fortunately it tends to be rare.

The point was that these were identified as being responsible for the majority of the bugs in a large, real-world code base.  Clearly #2 and #3 are common enough and cause enough issues to have made the list.

  -- Daniel
March 04, 2009
Daniel Keep wrote:
> The point was that these were identified as being responsible for the majority of the bugs in a large, real-world code base.  Clearly #2 and #3 are common enough and cause enough issues to have made the list.

A sample size of one doesn't mean much.  In my experience, none of those four factors account for a significant amount of bugs, since all of them (except integer overflow) can be caught without too much effort through the copious use of assertions.

I'd still prefer non-nullable references to be the default though. Writing an assertion for every non-nullable reference argument for every function is tedious.


-- 
Rainer Deyke - rainerd@eldwood.com
March 04, 2009
Rainer Deyke wrote:
> Writing an assertion for every non-nullable reference argument for every
> function is tedious.

It's also quite unnecessary. The hardware will do it for you, and the debugger will tell you where it is.

The hardware won't help you with array overflows or uninitialized variables, however.

March 04, 2009
Walter Bright wrote:
> Rainer Deyke wrote:
>> Writing an assertion for every non-nullable reference argument for every
>> function is tedious.
> 
> It's also quite unnecessary. The hardware will do it for you, and the debugger will tell you where it is.
> 
> The hardware won't help you with array overflows or uninitialized variables, however.
> 
In most of my experience, #2 is a special case of #4.
The worst case for an uninitialized variable is when it's a pointer; the best value (by far) that such an a uninitialized pointer can have is null.
OTOH I find that null references are an order of magnitude more common in D than in C++. I think that's significant, because in my experience, it's the only category of bugs which is worse in D.
It's far too easy to declare a class and forget to 'new' it.
March 04, 2009
"Walter Bright" <newshound1@digitalmars.com> wrote in message news:gole1d$23v4$1@digitalmars.com...
> Rainer Deyke wrote:
>> Writing an assertion for every non-nullable reference argument for every function is tedious.
>
> It's also quite unnecessary. The hardware will do it for you, and the debugger will tell you where it is.
>

Yes...at run-time. And even then only if you're lucky enough to hit all of the code paths that lead to a null-reference during testing. It might not cause data-corruption, but it does cause a crash. A crash might not typically be as bad as data-corruption, but both are still unnaceptable in professional software. Plus, a crash *can* be nearly as bad, if not equally bad, as data-corruption when it occurs in something mission-critical. This is not a problem to be taken lightly.


March 04, 2009

Walter Bright wrote:
> Rainer Deyke wrote:
>> Writing an assertion for every non-nullable reference argument for every function is tedious.
> 
> It's also quite unnecessary. The hardware will do it for you, and the debugger will tell you where it is.

You're missing the point.  It's not the moment at which the dereference happens that's the problem.  As you point out, we have a hardware trap for that.

It's when a null *gets assigned* to a variable that isn't ever supposed to *be* null that's the problem.  That's when the "asserts up the posterior" issue comes in, because it's the only mechanism we have for defending against this.

I need to know when that null gets stored, not when my code trips over it and explodes later down the line.

Non-nullable types (or proxy struct or whatever) means the code won't even compile if there's an untested path.  And if we do try to assign a null, we get an exception at THAT moment, so we can trace back to find out where it came from.

  -- Daniel