Proposal : allocations made easier with non nullable types.

Daniel Keep daniel.keep.lists at gmail.com
Mon Feb 9 17:50:49 PST 2009



Alex Burton wrote:
> Daniel Keep Wrote:
> 
>>
>> Alex Burton wrote:
>>> I think it makes no sense to have nullable pointers in a high level language like D.
>> Oh, and how do you intend to make linked lists?  Or trees?  Or any
>> non-trivial data structure?
> 
> I am not saying than null pointers should be barred - I don't think it would be possible.
> To implement the above, in a tree you will probably have arrays of pointers, each element of the array should be a valid pointer, and never null.
> To implement a linked list, I agree that a null pointer is a good implementation. You could still have the X * x = 0; pointer syntax for implementing special low level stuff like this.
> For the majority of uses allowing null references is not necessary.

So you're suggesting dynamically allocating a dynamically sized array
for each node in, say, a binary tree.  I really hope you never run into
my data structures and algorithms lecturer... I can't imagine that idea
would go over well. :P

Incidentally, "X* x = 0;" doesn't work in D.  Only "X* x = null;" will
work, since 0 is an integer literal, not a pointer literal...

>> Saying they have no place in a language is just silly; the question
>> should be whether they should be the default or not (I would contend
>> that they shouldn't be.)

You didn't respond to this comment; the bit about using arrays in a tree
above says to me that you want to push null as far out of the language
as technically feasible, no matter the cost.

Nullable references are a tool.  I'm agreeing with you on the idea that
it's the WRONG tool by default, but that doesn't mean we need to
demonise it.  It is useful in cases where it's appropriate, and would be
nigh impossible to replace.

>>> In D :
>>>
>>> X x = new X;
>>> This is a bit redundant, if we take away the ability to write X x; to mean X x = 0; then we can have X x; mean X x = new X;
>>> If the class has a ctor then we can write X x(32); instead of X x = new X(32);
>> Can I just say that I *LOATHE* this syntax?  It's one thing I always
>> despised about C++; it simply makes NO sense whatsoever.  It looks like
>> the bastard offspring of a function declaration and a function call.
> 
> Does that mean you loathe it in D now for structs too or just if it was implemented for classes ?

I loathe this:

> X x(32);

Maybe it's a matter of being used to it, but there is no way I can look
at that and say "yup, looks like initialisation."  After all, it's only
one token away from this:

> x(32);

And that's a function call.  Or one token away from this:

> X.x(32);

It just looks like too many other completely different things to be able
to fit in the "initialisation"-shaped hole I have in my head.  For
reference, when I see

> X x;

I mentally rewrite that to:

> X x = X.init;

No assignment, no initialisation.

>> The first *is* redundant, but then I wouldn't state X twice, I'd use
>> "auto" (because types are almost never a single letter anyway.)  Add to
>> that that the existing syntax is much more intuitive; it even reads like
>> a sentence.
> 
> I think that is personal taste. The sentance starting with the word auto doesn't make much sense to me.

Not entirely; your example did contain redundancy, but only because you
didn't use 'auto'.  I'm demonstrating that in D, saying 'X x = new X;'
is redundant is an invalid argument because you CAN omit the type, at
which point there is no redundancy.

But there is a level of personal preference at play here, I admit.  I
don't like "X x(32);" and you don't like "auto"... I guess we're evenly
matched.  :)

>>> As I said in the nullable types thread:
>>> Passing 0 or 0x012345A or anything else that is not a pointer to an instance of X to a variable declared as X x is the same as mixing in a bicycle when a recipe asks for a cup of olive oil.
>> Passing garbage to a function doesn't have any bearing on the
>> non-nullable discussion.  If you're casting random integers to pointers
>> and passing them to functions, you reap what you sow. :)
> 
> My point was that 0 is just as much not a pointer to an instance of X as 0x012456 is (unless you are quite lucky :))
> 
>> That said, passing null is more like omitting an ingredient.  Which is
>> unfortunate if you're making soup and the ingredient is "water."

What I was saying was that sometimes the concept of "nothing" is useful;
FAR more useful than the concept of "bicycle", by which I mean "random
garbage."  I can't think of any situation where passing a random pointer
is useful, but plenty of cases where passing "nothing" is.

>>> There are much better, and less error prone ways to write code in a high level language than allowing null pointers.
>>>
>>> Alex
>> While I'm a strong believer in non-nullable types, I don't think null
>> pointers are evil.  They're a tool like anything else; problems only
>> arise when you misue them.
>>
>> I believe they're the wrong default choice, because they don't come up
>> in normal code, but you've got to fall over yourself to make sure they
>> don't become an issue.
>>
>> Let me chip in a practical example that happened just yesterday.
>>
>> I'm throwing together a game prototype.  Since this is C#, I don't have
>> contracts, so I'm making judicious use of Debug.Assert calls to ensure
>> that object references are non-null.
>>
>> And surprise, surprise, my program crashes with null dereference errors.
>>  I walk the stack trace back, only to discover that the null got stored
>> at some point.  So the program doesn't even crash when the problem
>> occurs (storing a null reference in a field that shouldn't have one) it
>> occurs later in the execution when I'm no longer able to easily
>> determine what went wrong.
>>
>> Eventually, I tracked it down to one of the few places in the code that
>> I forgot to assert the reference was non-null.  It was null because
>> Microsoft didn't bother to document that a particular "magic object"
>> doesn't exist until a certain point.
> 
> Doesn't this prove my point ?

You may not have noticed, but:

>> While **I'm a strong believer in non-nullable types**, I don't think
>> null pointers are evil.  They're a tool like anything else; problems
>> only arise when you misue them.

I'm *agreeing* with you that non-nullable should be default.  What I was
arguing against was the apparent suggestion to outlaw the null pointer
on pain of death.

Indeed, the example DOES support the "non-nullable by default" argument,
hence why I posted it.

> You are littering code with Debug.Assert statements to check the assumption that pointers are non null.
> It is much easier to manage code where you can safely assume that all pointers point to something, which is one of the great benefits about the garbage collector.
> 
> If you really want to write some small subset of code with a nullable type then I suggest write a little template smart pointer for it, that forces you to explicitly check if it is null before using it.
> Like this:
> 
> [snip]
> 
> Sorry about the syntax - I havent done templates in D yet (probably this says a lot about the improvements over C++).
> 
> Alex

How do you propose to write a template implementing nullable types when
you aren't ALLOWED to use null?  You'd have to start casting around
between integers and references, which is arguably worse than just
supporting nullable types.

Incidentally, you cannot implement non-nullable types in D either, which
suggests that we need language-level support for both.

Also, FYI, these two lines:

> struct Nullable<T>
> void f(nullable!X x)

Should be:

> struct Nullable(T)
> void f(nullable!(X) x)

Note that I tested that second one with a D 1.x compiler; if it's valid
in D 2.x, I'm not aware of it.  :)

  -- Daniel



More information about the Digitalmars-d mailing list