On Mon, 09 Feb 2009 01:19:55 +0300, Bartosz Milewski <bart...@relisoft.com> 
wrote:

I also believe that non-null should be the default. Most references in a typical program are assumed to be non-null.


Oh, that's true!

Like for every default, there should be an escape mechanism from it. However, adding "nullable" to the type system might be controversial, especially because it requires special treatment of constructors and polymorphism (hence additional type modifiers, raw and poly-null, and I haven't even mentioned wildcard annotations).


Common opinion is that this is worth the trouble these days. More and more 
people discuss, write articles on non-nullable types and incorporate them into 
languages. Main C# architects has stated that absence of non-nullable types by 
default is his greatest mistake that is too late to be fixed.

So some time ago I came up with a more modest proposal. The compiler should catch nullable references at their source. It should enforce what I call "declaration is initialization" (DII). For instance, the following is correct:

Foo foo = new Foo;

and the following is not:

Foo foo; // error
...
foo = new Foo;

Obviously this rule is too strict, so there must be a way to override it. Here's the simple syntax:

Foo foo = null; // not an error!


And what about value types? Why special treatment for reference types only? I 
don't like rules like that in a language:

Foo foo; // error
int i; // okay?

If not, and this is an error, too, then this defeats the whole purpose of 
having T.init in D, because it will never be used per your proposal:

int i = 0; // initialized explicitly
char c = char.init; // would you use that?

Notice that the programmer explicitly states that one should be careful when using foo, because it might be null.

Since this solution doesn't involve the type system, the nullability doesn't propagate across function calls. But it might be a tradeoff worth taking, if only for the simplicity.


Naah.. The whole purpose of having non-nullable types is that given a pointer 
you are sure it is not null:

string toString(Object o)
{
  // is it null or not? Should I check for null or not? What if it is null?
  // Should I throw? What kind of exception?
  // But was going to make it nothrow! So what, no checks?
  // Just fail with access violation? Is this the best D can do?

  return o.toString();
}

As an end user, you neglect and avoid null checks in your code ("I'm sure I won't 
pass null here"). And then you run your program half an hour, it segfaults with 
access violation and you don't have any clue where did null dereference take place. I 
have came across this situation so many times that I hate it.

As a library designer, you end up having null checks everywhere in your code 
which is some kind of a paranoia because in 99% of cases the pointer will be 
not null. But why put so many special case and checks if it is *disallowed* to 
run code with null pointer in first place? So people decided - let's enforce 
that at compile time! That's the whole point of the feature - disallow invalid 
use cases at compile time. You get cleaner code (no unnecessary null-checks and 
throws) and small performance improvement as a bonus.

I would like to write code as this as be sure that it will never fail:

string toString(Object o) // non-nullability is enforced at compile time
{
   return o.toString();
}

This is D style - do as much as possible at compile time - and I believe 
non-nullable types fit D type system very well.

Constructors still need some special treatment. Every class member variable must be initialized in the constructor. Again, the escape is to _explicitly_ initialize it to null. This might seem redundant, since the variable is already default initialized to null, but the compiler can easily eliminate such redundancies.

I also found out that Java's editor, Eclipse, enforces DII--a very useful feature that paid off for me in the first 100 lines of code I wrote after a long period of inactivity in Java ;-)

Michel Fortin Wrote:

In fact, I'd even argue that non-nullability should be the default for
pointers and class references, because it is either safer (if the
compiler doesn't do the null check for you) or less troublesome to use
(if the compiler forces you to check for null everytime). Another
reason being consistency: value-types can't be null by default and so
should be class references and pointers. And making pointers
non-nullable by default can only be done at the language level, so
obviously it's better in the language than as a user-defined type
modifier.



Reply via email to