www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Null references

reply "bearophile" <bearophileHUGS lycos.com> writes:
The very good Mark C. Chu-Carroll has written a little blog post 
about the lack of null-related errors in his Scala code:

http://scientopia.org/blogs/goodmath/2012/08/20/nulls/

Bye,
bearophile
Aug 21 2012
next sibling parent "Regan Heath" <regan netmail.co.nz> writes:
On Tue, 21 Aug 2012 12:32:31 +0100, bearophile <bearophileHUGS lycos.com>  
wrote:

 The very good Mark C. Chu-Carroll has written a little blog post about  
 the lack of null-related errors in his Scala code:

 http://scientopia.org/blogs/goodmath/2012/08/20/nulls/

This article links to: http://beust.com/weblog/2012/08/19/a-note-on-null-pointers/ very early on. Which is also a good read, and has parallels with the NaN discussion as well :p I really like the Groovy/Fantom/Kotlin syntax shown: [quote] For example, here is how Kotlin lets you ignore null values encountered along a chain of invocations: bob?.department?.head?.name If either of these accesses returns null, the result of this expression will be null. No need to put your values into monadic boxes nor mapping through them, just use the standard composition operator you are familiar with if you are using a C family language. [/quote] I think this would be a neat D feature. R -- Using Opera's revolutionary email client: http://www.opera.com/mail/
Aug 21 2012
prev sibling parent reply "Regan Heath" <regan netmail.co.nz> writes:
On Tue, 21 Aug 2012 12:32:31 +0100, bearophile <bearophileHUGS lycos.com>  
wrote:

 The very good Mark C. Chu-Carroll has written a little blog post about  
 the lack of null-related errors in his Scala code:

 http://scientopia.org/blogs/goodmath/2012/08/20/nulls/

It's prob no obvious from my other reply, but you might have guessed, I'm of the opinion that Otaku, Cedric's blog post is spot on and Mark C is wrong. Well, not wrong exactly but not right either. A Null pointer exception in Java will give you a stack trace, meaning you can be sure which method triggered it, meaning you don't have to examine "everything", just those method calls/objects used therein. If your method is so large that this is a daunting task, then you're already doing something wrong. Plus, I don't buy the argument that having to explicitly type ".get" will stop anyone from automatically coding statements like: val g: Option[T] = f.doSomething() g.get.doSomethingElse() and suffering the exact same null pointer exception/error despite using Option and boxing into a Not-Null type. Like checked exceptions people will simply ignore the possibility of error and type the above anyway. So, end result, it's just more typing for no real gain. On the other hand, the suggested syntax of "bob?.department?.head?.name" from Kotlin is pure genius, and has a good chance of actually being used. R -- Using Opera's revolutionary email client: http://www.opera.com/mail/
Aug 21 2012
next sibling parent reply "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On Tue, 21 Aug 2012 13:55:58 +0200, Regan Heath <regan netmail.co.nz>  
wrote:

 I don't buy the argument that having to explicitly type ".get" will stop  
 anyone from automatically coding statements like:

 val g: Option[T] = f.doSomething()
 g.get.doSomethingElse()

So don't give them that access? I have an Option struct on my home computer that only allows access to the held value if the error case is simultaneously handled: Option!int a = foo(); int n = a.match!( (int x) => x, (None n) => 0 // or throw, or what have you. ); The same solution is perfectly adaptable to MaybeNull, MaybeNan, and probably a host of others of the same family. With some clever use of opDispatch, one could write an Option struct that lets you call methods and acces members of the wrapped type, and return Option!ReturnType.
 On the other hand, the suggested syntax of "bob?.department?.head?.name"  
  from Kotlin is pure genius, and has a good chance of actually being  
 used.

Absolutely. Probably hard to include in D though, as a ? .b is the beginning of a conditional expression. -- Simen
Aug 21 2012
next sibling parent reply "Carl Sturtivant" <sturtivant gmail.com> writes:
 On the other hand, the suggested syntax of 
 "bob?.department?.head?.name" from Kotlin is pure genius, and 
 has a
 good chance of actually being used.

Absolutely. Probably hard to include in D though, as a ? .b is the beginning of a conditional expression.

How about bob??.department??.head??.name
Aug 21 2012
next sibling parent reply "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On Tue, 21 Aug 2012 16:08:23 +0200, Carl Sturtivant <sturtivant gmail.com>  
wrote:

 On the other hand, the suggested syntax of  
 "bob?.department?.head?.name" from Kotlin is pure genius, and has a
 good chance of actually being used.

Absolutely. Probably hard to include in D though, as a ? .b is the beginning of a conditional expression.

How about bob??.department??.head??.name

I guess that could work. Still won't happen though, but for other reasons. Also, reminded me of C's WTF operator: foo ??!??! exit(1); -- Simen
Aug 21 2012
parent "Peter Alexander" <peter.alexander.au gmail.com> writes:
On Tuesday, 21 August 2012 at 14:29:56 UTC, Simen Kjaeraas wrote:
 On Tue, 21 Aug 2012 16:08:23 +0200, Carl Sturtivant 
 <sturtivant gmail.com> wrote:

 On the other hand, the suggested syntax of 
 "bob?.department?.head?.name" from Kotlin is pure genius, 
 and has a
 good chance of actually being used.

Absolutely. Probably hard to include in D though, as a ? .b is the beginning of a conditional expression.

How about bob??.department??.head??.name

I guess that could work. Still won't happen though, but for other reasons. Also, reminded me of C's WTF operator: foo ??!??! exit(1);

That's brilliant. Surprised I haven't seen that before.
Aug 21 2012
prev sibling parent "Regan Heath" <regan netmail.co.nz> writes:
On Tue, 21 Aug 2012 15:08:23 +0100, Carl Sturtivant <sturtivant gmail.com>  
wrote:

 On the other hand, the suggested syntax of  
 "bob?.department?.head?.name" from Kotlin is pure genius, and has a
 good chance of actually being used.

Absolutely. Probably hard to include in D though, as a ? .b is the beginning of a conditional expression.

How about bob??.department??.head??.name

Hmm.. c# has another nice use for ?? http://msdn.microsoft.com/en-us/library/ms173224.aspx R -- Using Opera's revolutionary email client: http://www.opera.com/mail/
Aug 21 2012
prev sibling next sibling parent reply Nick Treleaven <nospam example.net> writes:
On 21/08/2012 14:30, Simen Kjaeraas wrote:
 On Tue, 21 Aug 2012 13:55:58 +0200, Regan Heath <regan netmail.co.nz>
 wrote:

 I don't buy the argument that having to explicitly type ".get" will
 stop anyone from automatically coding statements like:

 val g: Option[T] = f.doSomething()
 g.get.doSomethingElse()

So don't give them that access?

Yes, or force conversion of the Option, handling the invalid case: g.valueOrElse(null).doSomethingElse(); The above being explicit that null might be returned. The code is no safer, but it is much clearer. Also sometimes the caller has a better alternative value than null to use which is actually valid.
 I have an Option struct on my home computer that only allows access to
 the held value if the error case is simultaneously handled:

 Option!int a = foo();

 int n = a.match!(
      (int x) => x,
      (None n) => 0 // or throw, or what have you.
      );

 The same solution is perfectly adaptable to MaybeNull, MaybeNan, and
 probably
 a host of others of the same family.

 With some clever use of opDispatch, one could write an Option struct that
 lets you call methods and acces members of the wrapped type, and return
 Option!ReturnType.

Apart from the opDispatch bit, I've been slowly working on something similar (Boost license): https://github.com/ntrel/d-maybe/blob/master/maybe.d I'm still working on it, but the basic ideas are there. I think the best bit is apply(), which supports passing multiple Maybe values, calling the delegate only if all Maybes are valid. In fact Maybe.map() is unnecessary due to apply(). Nick
Aug 21 2012
next sibling parent reply Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Tue, Aug 21, 2012 at 10:17 PM, Nick Treleaven <nospam example.net> wrote:
 On 21/08/2012 14:30, Simen Kjaeraas wrote:

 I have an Option struct on my home computer that only allows access to
 the held value if the error case is simultaneously handled:

 Option!int a = foo();

 int n = a.match!(
      (int x) => x,
      (None n) => 0 // or throw, or what have you.
      );

 The same solution is perfectly adaptable to MaybeNull, MaybeNan, and
 probably
 a host of others of the same family.

 With some clever use of opDispatch, one could write an Option struct that
 lets you call methods and acces members of the wrapped type, and return
 Option!ReturnType.

Apart from the opDispatch bit, I've been slowly working on something similar (Boost license): https://github.com/ntrel/d-maybe/blob/master/maybe.d I'm still working on it, but the basic ideas are there. I think the best bit is apply(), which supports passing multiple Maybe values, calling the delegate only if all Maybes are valid. In fact Maybe.map() is unnecessary due to apply().

Then, both Simen and you could code a generic algebraic datatype generator, with the associated matching functions (and probably mapping / reducing) Here come the whole Haskell / ML menagerie of types :) mixin(ADT(" Tree(T): Leaf(T) | Branch(Tree, Tree) ")); or something like that... And then encode JSON like this. Or update std.typecons.Algebraic to make it deal with recursive definitions...
Aug 22 2012
parent Nick Treleaven <nospam example.net> writes:
On 22/08/2012 16:42, Philippe Sigaud wrote:
 Then, both Simen and you could code a generic algebraic datatype
 generator, with the associated matching functions (and probably
 mapping / reducing) Here come the whole Haskell / ML menagerie of
 types:)

 mixin(ADT("
 Tree(T):
      Leaf(T)
    | Branch(Tree, Tree)
 "));

 or something like that... And then encode JSON like this.

 Or update std.typecons.Algebraic to make it deal with recursive definitions...

Sounds interesting. I haven't really thought about modelling sum types yet - but I'm probably not the best person as I haven't actually used them in a functional language. I expect that D's meta-programming abilities will allow for some interesting things. BTW thanks for your template tutorial, it's been very helpful.
Aug 24 2012
prev sibling parent reply Nick Treleaven <nospam example.net> writes:
On 21/08/2012 21:17, Nick Treleaven wrote:
 I have an Option struct on my home computer that only allows access to
 the held value if the error case is simultaneously handled:

 Option!int a = foo();

 int n = a.match!(
      (int x) => x,
      (None n) => 0 // or throw, or what have you.
      );


I've now implemented match, similar to the above: https://github.com/ntrel/d-maybe/blob/master/maybe.d#L222 My match() always returns Maybe!T, because for pointers the lambdas could return null. Taken from the unittest: assert(match!(to!string, ()=>"<invalid>")(maybe(2)) == "2"); assert(match!(to!string, ()=>"<invalid>")(Maybe!int()) == "<invalid>"); assert(match!((x, y)=>text(x, y), {})(maybe(2), maybe(34)) == "234"); assert(match!((x, y)=>text(x, y), {})(Maybe!int(), maybe(34)) == null); assert(match!((x, y)=>text(x, y), ()=>"none")(Maybe!int(), maybe(34)) == "none"); I'd be interested to see your Option code. Nick
Aug 23 2012
next sibling parent reply "Namespace" <rswhite4 googlemail.com> writes:
Is there any special reason why these functions doesn't get 
"Maybe" as (const) ref?

void show(T)(Maybe!T m)
bool opEquals(Maybe!T m)
void opAssign(Maybe!T m)
Aug 23 2012
parent Nick Treleaven <nospam example.net> writes:
On 23/08/2012 18:27, Namespace wrote:
 Is there any special reason why these functions doesn't get "Maybe" as
 (const) ref?

 void show(T)(Maybe!T m)
 bool opEquals(Maybe!T m)
 void opAssign(Maybe!T m)

No special reason. The Maybe struct is usually pretty small so using ref didn't occur to me, but if it's good practice I should do so. I suppose ref would be necessary because T could be a struct. I hadn't thought about const at all yet. BTW show is just a test function, I recently made it private. Nick
Aug 24 2012
prev sibling parent "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On Thu, 23 Aug 2012 18:27:41 +0200, Nick Treleaven <nospam example.net>  
wrote:

 I'd be interested to see your Option code.

Here you go. After looking at your code, and with Modern C++ Design fresh in mind, I see that match and hasValue might have worked better as free functions. I took the liberty of implementing the optional function calls discussed earlier. If your eyes glaze over or you feel an urge to kill, you are likely looking at that part of the code. -- Simen
Aug 23 2012
prev sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 08/21/2012 06:30 AM, Simen Kjaeraas wrote:
 On Tue, 21 Aug 2012 13:55:58 +0200, Regan Heath <regan netmail.co.nz>
 wrote:

 On the other hand, the suggested syntax of
 "bob?.department?.head?.name" from Kotlin is pure genius, and has a
 good chance of actually being used.

Absolutely. Probably hard to include in D though, as a ? .b is the beginning of a conditional expression.

There are many characters that has been neglected by D: bob⸮.department⸮.head⸮.name :p (If not visible on your screen, that character is U+2E2E.) Ali
Aug 21 2012
parent "Carl Sturtivant" <sturtivant gmail.com> writes:
 There are many characters that has been neglected by D:

   bob⸮.department⸮.head⸮.name

 :p (If not visible on your screen, that character is U+2E2E.)

 Ali

Nice! No-one of the Ascii-Trapped would miss that: self documentation indeed.
Aug 21 2012
prev sibling next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Regan Heath:

 Plus, I don't buy the argument that having to explicitly type 
 ".get" will stop anyone from automatically coding statements 
 like:

 val g: Option[T] = f.doSomething()
 g.get.doSomethingElse()

 and suffering the exact same null pointer exception/error 
 despite using Option and boxing into a Not-Null type.

 Like checked exceptions people will simply ignore the 
 possibility of error and type the above anyway.  So, end 
 result, it's just more typing for no real gain.

Mark C. Chu-Carroll is very intelligent and well read, most times he's right. My Scala experience is limited, so I don't first-hand how much Mark is right this time. I think having a type for a reference/pointer that can't be null is useful. With it in many situations you need no "get", because there no risk of it being null. So the discussion here is for the other cases where you need a reference that can be null too. Such cases are surely just part of the cases where in D now you receive a generic nullable reference/pointer. So even if "get" is about as dangerous as normal references, the situation is better still. Time ago I have suggested a syntax like Foo to represent in D the subtype of Foo references that can't be null. Bye, bearophile
Aug 21 2012
parent "Namespace" <rswhite4 googlemail.com> writes:
 Time ago I have suggested a syntax like Foo  to represent in D 
 the subtype of Foo references that can't be null.

That would be nice. Anyhow a lot better as any library solution. But I think it will be resulting in a NotNullable struct in std.typecons...
Aug 22 2012
prev sibling next sibling parent Ziad Hatahet <hatahet gmail.com> writes:
On Tue, Aug 21, 2012 at 4:55 AM, Regan Heath <regan netmail.co.nz> wrote:

 Plus, I don't buy the argument that having to explicitly type ".get" will
 stop anyone from automatically coding statements like:

 val g: Option[T] = f.doSomething()
 g.get.doSomethingElse()

 and suffering the exact same null pointer exception/error despite using
 Option and boxing into a Not-Null type.


 R

C++ and D have language constructs to allow you to cast away const-ness and immutability, does that mean we have to do away with the concept just because there is a way around it? -- Ziad
Aug 22 2012
prev sibling parent "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On Wed, 22 Aug 2012 19:37:09 +0200, Ziad Hatahet <hatahet gmail.com> wrote:

 C++ and D have language constructs to allow you to cast away const-ness  
 and
 immutability, does that mean we have to do away with the concept just
 because there is a way around it?

No, but a cast sticks out like a sore thumb. foo.get().bar() does not. -- Simen
Aug 22 2012