View mode: basic / threaded / horizontal-split · Log in · Help
September 27, 2009
Re: Null references redux
Andrei Alexandrescu wrote:
> Walter Bright wrote:
>> The problem with non-nullable references is what do they default to? 
>> Some "nan" object? When you use a "nan" object, what should it do? 
>> Throw an exception?
> 
> This is the mistake. There would no way to default initialize a non-null 
> object. I'm surprised you are still saying this, because we discussed 
> how NonNull!T could be implemented by disabling its default constructor.

Sure, so the user just provides "0" as the argument to the non-default 
constructor. Or he writes:

    C c = c_empty;

using c_empty as his placeholder for an empty object. Now, what happens 
with:

    c.foo();

? Should c_empty throw an exception? To take this a little farther, 
suppose I wish to create an array of C that I will partially fill with 
valid data, and leave some empty slots. Those empty slots I stuff with 
c_empty, to avoid having nulls. What is c_empty's proper behavior if I 
mistakenly try to access its members?

Forcing the user to provide an initializer does not solve the problem. 
The crucial point is the problem is *not* the seg fault, the seg fault 
is the symptom. The problem is the user has not set the object to a 
value that his program's logic requires.


I am also perfectly happy with NonNull being a type constructor, to be 
used where appropriate. My disagreement is with the notion that null 
references should be eliminated at the language level.
September 27, 2009
Re: Null references redux
Yigal Chripun wrote:
> An exception trace is *far* better than a segfault and that does not 
> require null values.

Seg faults are exceptions, too. You can even catch them (on windows)!
September 27, 2009
Re: Null references redux
Walter Bright wrote:
> Andrei Alexandrescu wrote:
>> Walter Bright wrote:
>>> The problem with non-nullable references is what do they default to? 
>>> Some "nan" object? When you use a "nan" object, what should it do? 
>>> Throw an exception?
>>
>> This is the mistake. There would no way to default initialize a 
>> non-null object. I'm surprised you are still saying this, because we 
>> discussed how NonNull!T could be implemented by disabling its default 
>> constructor.
> 
> Sure, so the user just provides "0" as the argument to the non-default 
> constructor. Or he writes:
> 
>     C c = c_empty;
> 
> using c_empty as his placeholder for an empty object. Now, what happens 
> with:
> 
>     c.foo();
> 
> ? Should c_empty throw an exception?

The problem is you keep on insisting on one case "I have a non-null 
reference that I don't have an initializer for, but the compiler forces 
me to find one, so I'll just throw a crappy value in." This focus on one 
situation comes straight with your admitted bad habit of defining 
variables in one place and initializing in another. The situation you 
need to open a curious eye on is "I have a reference that's never 
supposed to be null, but I forgot about initializing it and the compiler 
silently put a useless null in it." The simplest case is what _every_ D 
beginner has done:

T x;
x.fun();

to witness a crash. Why the hell does that crash? It did work when T was 
a struct. (Also this damns generic code to hell.)

So again: focus on the situation when people forget to initialize 
references that are never supposed to be null.

That has happened to me, and I'm supposed to know about this stuff. And 
one thing you don't understand is that on Linux, access violations are 
much more difficult to figure than others. On a computing cluster it 
gets one order of magnitude more difficult. So spare me of your Windows 
setup that launches your debugger on the line of the crash. For better 
or worse, many don't have that. People sometimes have problems that you 
don't have, and you need to put yourself in their shoes.

> To take this a little farther, 
> suppose I wish to create an array of C that I will partially fill with 
> valid data, and leave some empty slots. Those empty slots I stuff with 
> c_empty, to avoid having nulls. What is c_empty's proper behavior if I 
> mistakenly try to access its members?

You make an array of nullable references. Again you confuse having 
non-null as a default with having non-null as the only option.

> Forcing the user to provide an initializer does not solve the problem. 
> The crucial point is the problem is *not* the seg fault, the seg fault 
> is the symptom. The problem is the user has not set the object to a 
> value that his program's logic requires.
> 
> 
> I am also perfectly happy with NonNull being a type constructor, to be 
> used where appropriate. My disagreement is with the notion that null 
> references should be eliminated at the language level.

Null references shouldn't be eliminated from the language. They just 
should NOT be the default. I guess I'm going to say that until you tune 
on my station.


Andrei
September 27, 2009
Re: Null references redux
Walter Bright wrote:
> ...
> 
> It all depends on what you prefer a program to do when it encounters a
> program bug:
> 
> 1. Immediately stop and produce an indication that the program failed
> 
> 2. Soldier on and silently produce garbage output
> 
> I prefer (1).
> 
> ...

*sigh*  Walter, I really admire you as a programmer.  But this is about
the most blatant strawman argument I've seen in a while.

Firstly, as others have indicated, the whole point of non-null would be
to REQUIRE initialisation to something useful.

"But the user will just assign to something useless to get around that!"

You mean like how everyone wraps every call in try{...}catch(Exception
e){} to shut the damn exceptions up?  Or uses pointer arithmetic and
casts to get at those pesky private members?

If someone is actively trying to break the type system, it's their
goddamn fault!  Honestly, I don't care about the hacks they employ to
defeat the system because they're going to go around blindly shooting
themselves in the foot no matter what they do.

It's like arguing that safety rails are pointless because people can
just jump over them.  BESIDES, if they fall off, you get this really
loud "crunch" followed by a shower of blood; then it's OBVIOUS that
something's wrong.

And what about the people who AREN'T complete idiots, who maybe
sometimes just accidentally trip and would quite welcome a safety rail
there?

Besides which, the non-null proposal is always accompanied by the
proposal to add nullable object references as T? (or whatever; the
syntax is irrelevant at this point).  If a programmer really wants a
null-initialised object reference, which is she more likely to do?

 class NullFoo : Foo
 {
   void member1() { throw new Exception("NULL!"); }
   void member2() { throw new Exception("NULL!"); }
   ...
 }

 Foo bar = new NullFoo;

or

 Foo? bar;

Since the reason they're trying to circumvent the non-null protection is
because of laziness, I assert they're far more likely to go with the
second than the first.

And it's STILL better because you couldn't implicitly cast between Foo?
and Foo.  They would HAVE to insert an explicit cast or check.

 Foo quxx = enforceNN(bar);

Finally, let me re-post something I wrote the last time this came up:

> The problem with null dereference problems isn't knowing that they're
> there: that's the easy part.  You helpfully get an exception to the
> face when that happens. The hard part is figuring out *where* the
> problem originally occurred. It's not when the exception is thrown
> that's the issue; it's the point at which you placed a null reference
> in a slot where you shouldn't have.
>
> Yes, we have invariants and contracts; but inevitably you're going to
> forget one, and it's that one slip-up that's going to bite you in the
> rear.
>
> One could use roughly the same argument for non-null references as for
> const: you could document it, but documentation is inevitably wrong or
> out of date.  :P
September 27, 2009
Re: Null references redux
Andrei Alexandrescu wrote:
> [snip]
> The problem is you keep on insisting on one case "I have a non-null 
> reference that I don't have an initializer for, but the compiler forces 
> me to find one, so I'll just throw a crappy value in." This focus on one 
> situation comes straight with your admitted bad habit of defining 
> variables in one place and initializing in another. The situation you 
> need to open a curious eye on is "I have a reference that's never 
> supposed to be null, but I forgot about initializing it and the compiler 
> silently put a useless null in it." The simplest case is what _every_ D 
> beginner has done:
> 
> T x;
> x.fun();
> 
> to witness a crash. Why the hell does that crash? It did work when T was 
> a struct. (Also this damns generic code to hell.)
> 
> So again: focus on the situation when people forget to initialize 
> references that are never supposed to be null.
> 
> That has happened to me, and I'm supposed to know about this stuff. And 
> one thing you don't understand is that on Linux, access violations are 
> much more difficult to figure than others. On a computing cluster it 
> gets one order of magnitude more difficult. So spare me of your Windows 
> setup that launches your debugger on the line of the crash. For better 
> or worse, many don't have that. People sometimes have problems that you 
> don't have, and you need to put yourself in their shoes.

Quoted for truth.


-- 
Tomasz Stachowiak
http://h3.team0xf.com/
h3/h3r3tic on #D freenode
September 27, 2009
Re: Null references redux
Hello Walter,

> The problem with non-nullable references is what do they default to?
> Some "nan" object? When you use a "nan" object, what should it do?
> Throw an exception?
> 

They don't have a default. There semantics would be such that the compiler 
rejects as illegal any code that would require it to supply a default.

As to the user stuffing "c_empty" in just to get the compiler to shut up; 
firstly, that says the variable should not yet be declared as you don't yet 
known what value to give it and secondly either c_empy is a rational value 
or the user is subverting the type system and is on there own.
September 27, 2009
Re: Null references redux
Walter Bright wrote:
> Denis Koroskin wrote:
>  > On Sat, 26 Sep 2009 22:30:58 +0400, Walter Bright
>  > <newshound1@digitalmars.com> wrote:
>  >> D has borrowed ideas from many different languages. The trick is to
>  >> take the good stuff and avoid their mistakes <g>.
>  >
>  > How about this one:
>  > 
> http://sadekdrobi.com/2008/12/22/null-references-the-billion-dollar-mistake/ 
> 
>  >
>  >
>  > :)
> 
> I think he's wrong.

Please, please, please, do some fun little project in Java or C# and 
drop the idea of initializing variables whenever you declare them. Just 
leave them like this:

int i;

and then later initialize them when you need them, for example different 
values depending on some conditions. Then you'll realize how powerful is 
having the compiler stop variables that are not initialized *in the 
context of a function, not necessarily in the same line of their 
declaration*. It's always a win: you get a compile time error, you don't 
have to wait to get an error at runtime.

Until you do that, you won't understand what most people are answering 
to you.

But I know what you'll answer. You'll say "what about pointers?", "what 
about ref parameters?", "what about out parameters?", and then someone 
will say to you "C# has them", etc, etc.

No point disussing non-null variables without also having the compiler 
stop uninitialized variables.
September 27, 2009
Re: Null references redux
Ary Borenszweig wrote:
> Walter Bright wrote:
>> Denis Koroskin wrote:
>>  > On Sat, 26 Sep 2009 22:30:58 +0400, Walter Bright
>>  > <newshound1@digitalmars.com> wrote:
>>  >> D has borrowed ideas from many different languages. The trick is to
>>  >> take the good stuff and avoid their mistakes <g>.
>>  >
>>  > How about this one:
>>  > 
>> http://sadekdrobi.com/2008/12/22/null-references-the-billion-dollar-mistake/ 
>>
>>  >
>>  >
>>  > :)
>>
>> I think he's wrong.
> 
> Please, please, please, do some fun little project in Java or C# and 
> drop the idea of initializing variables whenever you declare them. Just 
> leave them like this:
> 
> int i;
> 
> and then later initialize them when you need them, for example different 
> values depending on some conditions. Then you'll realize how powerful is 
> having the compiler stop

I meant "spot"
September 27, 2009
Re: Null references redux
Daniel Keep wrote:
> "But the user will just assign to something useless to get around that!"
> 
> You mean like how everyone wraps every call in try{...}catch(Exception
> e){} to shut the damn exceptions up?

They do just that in Java because of the checked-exceptions thing. I 
have a reference to Bruce Eckel's essay on it somewhere in this thread. 
The observation in the article was it wasn't just moron idiot 
programmers doing this. It was the guru programmers doing it, all the 
while knowing it was the wrong thing to do. The end result was the 
feature actively created the very problems it was designed to prevent.


> Or uses pointer arithmetic and
> casts to get at those pesky private members?

That's entirely different, because privacy is selected by the 
programmer, not the language. I don't have any issue with a user-defined 
type that is non-nullable (Andrei has designed a type constructor for that).


> If someone is actively trying to break the type system, it's their
> goddamn fault!  Honestly, I don't care about the hacks they employ to
> defeat the system because they're going to go around blindly shooting
> themselves in the foot no matter what they do.

True, but it's still not a good idea to design a language feature that 
winds up, in reality, encouraging bad programming practice. It 
encourages bad practice in a way that is really, really hard to detect 
in a code review.

I like programming mistakes to be obvious, not subtle. There's nothing 
subtle about a null pointer exception. There's plenty subtle about the 
wrong default value.


> And what about the people who AREN'T complete idiots, who maybe
> sometimes just accidentally trip and would quite welcome a safety rail
> there?

Null pointer seg faults *are* a safety rail. They keep an errant program 
from causing further damage.


> Finally, let me re-post something I wrote the last time this came up:
> 
>> The problem with null dereference problems isn't knowing that they're
>> there: that's the easy part.  You helpfully get an exception to the
>> face when that happens. The hard part is figuring out *where* the
>> problem originally occurred. It's not when the exception is thrown
>> that's the issue; it's the point at which you placed a null reference
>> in a slot where you shouldn't have.

It's a lot harder to track down a bug when the bad initial value gets 
combined with a lot of other data first. The only time I've had a 
problem finding where a null came from (because they tend to fail very 
close to their initialization point) is when the null was caused by 
another memory corruption problem. Non-nullable references won't 
mitigate that.
September 27, 2009
Re: Null references redux
Walter Bright wrote:
> Daniel Keep wrote:
>> "But the user will just assign to something useless to get around that!"
>>
>> You mean like how everyone wraps every call in try{...}catch(Exception
>> e){} to shut the damn exceptions up?
> 
> They do just that in Java because of the checked-exceptions thing. I 
> have a reference to Bruce Eckel's essay on it somewhere in this thread. 
> The observation in the article was it wasn't just moron idiot 
> programmers doing this. It was the guru programmers doing it, all the 
> while knowing it was the wrong thing to do. The end result was the 
> feature actively created the very problems it was designed to prevent.
> 
> 
>> Or uses pointer arithmetic and
>> casts to get at those pesky private members?
> 
> That's entirely different, because privacy is selected by the 
> programmer, not the language. I don't have any issue with a user-defined 
> type that is non-nullable (Andrei has designed a type constructor for 
> that).
> 
> 
>> If someone is actively trying to break the type system, it's their
>> goddamn fault!  Honestly, I don't care about the hacks they employ to
>> defeat the system because they're going to go around blindly shooting
>> themselves in the foot no matter what they do.
> 
> True, but it's still not a good idea to design a language feature that 
> winds up, in reality, encouraging bad programming practice. It 
> encourages bad practice in a way that is really, really hard to detect 
> in a code review.
> 
> I like programming mistakes to be obvious, not subtle. There's nothing 
> subtle about a null pointer exception. There's plenty subtle about the 
> wrong default value.
> 
> 
>> And what about the people who AREN'T complete idiots, who maybe
>> sometimes just accidentally trip and would quite welcome a safety rail
>> there?
> 
> Null pointer seg faults *are* a safety rail. They keep an errant program 
> from causing further damage.

Null pointer seg faults *not being able to happen* are much more safe. :)
2 3 4 5 6 7 8 9 10
Top | Discussion index | About this forum | D home