View mode: basic / threaded / horizontal-split · Log in · Help
February 10, 2009
Re: Proposal : allocations made easier with non nullable types.
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.

> 
> 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.)
> 
> > 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 ?

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


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

struct Nullable<T> //sorry don't know D syntax for this
{
private:
   T * value;
public
  this()
  {
    value = 0;
  }
  this(T val)
  {
    value = val;
  }
  T get()
  {
       if (value is null)
         throw NullableTypeException("value is null")
       else
         return value;
  }
  bool isnull()
  {
    return value is null;
  }
};


void f(nullable!X x)
{
  x.makeACupOfTea();    //wont compile.

  x.get().makeACupOfTea();   //will throw if null
  
  if (!x.isnull())
    x.get().makeACupOfTea();   //proper use of nullable type
}


Sorry about the syntax - I havent done templates in D yet (probably this says a lot about the improvements over C++).

Alex
February 10, 2009
Re: Proposal : allocations made easier with non nullable types.
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
February 10, 2009
Re: Proposal : allocations made easier with non nullable types.
Daniel Keep Wrote:

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

OK the point you make is that using nullable pointers is necessary.
I would agree, but say that all the examples you have given are at the library implementation level (code that most D developers probably wont want in what they do day to day).
IIRC D already has references like X x; but also pointers like in c which are X * x.

I would propose that library writers have to use the X * x pointer notation to do their null pointer low level library implementation stuff, and the rest of us use X x which becomes more difficult (not impossible) to make null.

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

Not as far as technically feasable, just that it should be opt in, and the simplest to type should be non nullable - the default as you suggest.
Sorry no demonisation intended.
Merely an intimation in the language that if you are dealing with nullable types you probably know what you are doing, as you are exposing yourself to error prone code.

> >>> 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.  :)

I was just pointing out that if we are looking at english sentances auto doesn't make much sense.
I do think that code with auto in it requires more searching to find the actual type of a variable. Not in auto x = new X; but in auto x = factory.create();

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

You're right I thought you wanted the default to stay as it is.
Must be my comprehension of the double negative "non nullable types" :)

No pain or death suggested.


> 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.
> 
In the code I wrote which might be considered for addition to a library.
I was using the T * val; notation which I would propose is still available to those that want nullable pointers.
Again it's use should be mostly limited to library implementation and wrapping C APIs etc.

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

Agreed the X * x = null; syntax is still good.

> Also, FYI, these two lines:
> 
> > struct Nullable<T>
> > void f(nullable!X x)
> 
> Should be:
> 
> > struct Nullable(T)
> > void f(nullable!(X) x)

Thanks !

> 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.  :)

So the only point of contetion between us is that you wont be happy with the syntax.
X x(32);
X x("bob");
Even though it is currently consistent with struct initialisation, and would save us all some typing.

Alex
February 10, 2009
Re: Proposal : allocations made easier with non nullable types.
"Alex Burton" <alexibu@mac.com> wrote in message 
news:gmqrec$2va3$1@digitalmars.com...
> I would propose that library writers have to use the X * x pointer 
> notation to do their null pointer low level library implementation stuff, 
> and the rest of us use X x which becomes more difficult (not impossible) 
> to make null.
>

So are you suggesting this?:

X* x; // Ok, can be null
X x; // Ok, cannot be null
X? x; // Illegal

If so, I'd have to strongly disagree. That would force the people who need 
nullability to muck around with the pointers and the extra level of 
indirection that implies, which will be far more problematic for them then 
if they just used a nullable non-pointer:

X? x;

We need all three.
February 10, 2009
Re: Proposal : allocations made easier with non nullable types.
"Daniel Keep" <daniel.keep.lists@gmail.com> wrote in message 
news:gmqmhk$2mb0$1@digitalmars.com...
>
> 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.
>

Devil's advocate:
---------------
struct Nullable(T)
{
  private T value; // Assuming "X x;" means "X x = new X();"
  private bool _isNull=true;

  void set(T val) {
      value = val;
      _isNull = false;
  }
  T get() {
      if (_isNull)
           throw NullableTypeException("value is null")
      else
           return value;
  }
  void makeNull() {
      _isNull = true;
  }
  bool isNull() {
      return _isNull;
  }
}
---------------

But admittedly, it's a kludge and vastly inferior to a nice well-implemented 
"X? x;" at the language level.
Top | Discussion index | About this forum | D home