www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Regarding Nullables

reply "bearophile" <bearophileHUGS lycos.com> writes:
This is a little Haskell program that uses the Maybe type 
constructor:


foo :: Int -> Maybe Int
foo x | x < 10 = Just x
foo _          = Nothing

main = do
     print $ foo 5
     print $ foo 15


Its output:

Just 5
Nothing




This is a similar D program, that uses Nullable:

import std.stdio, std.typecons;

Nullable!int foo(int x) {
     return (x < 10) ?
            typeof(return)(x) :
            typeof(return)();
}

void main() {
     writeln(foo(5));
     writeln(foo(15));
}


Its output:

5
core.exception.AssertError C:\dmd2\src\phobos\std\typecons.d(1515): 
Called `get' on null Nullable!int.
...


I think it's better for write(Nullable!int()) to not raise an 
error, but to print something like a "<null>" etc.

A bigger problem is in the usage of Nullable. I'd like the D type 
system to be modified and improved to support Nullables with a 
nicer syntax.

Bye,
bearophile
Sep 13 2014
next sibling parent "Meta" <jared771 gmail.com> writes:
On Saturday, 13 September 2014 at 15:36:30 UTC, bearophile wrote:
 This is a little Haskell program that uses the Maybe type 
 constructor:


 foo :: Int -> Maybe Int
 foo x | x < 10 = Just x
 foo _          = Nothing

 main = do
     print $ foo 5
     print $ foo 15


 Its output:

 Just 5
 Nothing




 This is a similar D program, that uses Nullable:

 import std.stdio, std.typecons;

 Nullable!int foo(int x) {
     return (x < 10) ?
            typeof(return)(x) :
            typeof(return)();
 }

 void main() {
     writeln(foo(5));
     writeln(foo(15));
 }


 Its output:

 5
 core.exception.AssertError C:\dmd2\src\phobos\std\typecons.d(1515): 
 Called `get' on null Nullable!int.
 ...


 I think it's better for write(Nullable!int()) to not raise an 
 error, but to print something like a "<null>" etc.

 A bigger problem is in the usage of Nullable. I'd like the D 
 type system to be modified and improved to support Nullables 
 with a nicer syntax.

 Bye,
 bearophile
I think Nullable should be completely replaced with an Option!T type that is also a range, and one that also doesn't `alias this` itself to its store. Then the above code would just print "[]" for an empty range. I'm sure you remember this thread: http://forum.dlang.org/thread/l87ivq$263r$1 digitalmars.com The problem is that Nullable internally has a `get` function that checks if it is "null", and throw an error if so. It then does `alias get this`, which means that in some contexts, operations will be forwarded to `get`, and I guess one of those contexts is when passing the Nullable to writeln. I've run into this problem before, and I *thought* it had been fixed, but I guess not.
Sep 13 2014
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/13/14, 8:36 AM, bearophile wrote:
 This is a little Haskell program that uses the Maybe type constructor:
[snip] As others noted, I think we need a kind of range with either zero or one element. Also, the range would have an "exception" property that returns null if the operation was successful (and the element is there) or whatever exception produced the result. E.g.: MaybeRange fun() { ... } ... auto r = fun; if (r.empty) { assert(r.exception); ... error case ... } else { ... use r.front ... r.popFront; assert(r.empty); // just one element } Andrei
Sep 13 2014
next sibling parent "Meta" <jared771 gmail.com> writes:
On Saturday, 13 September 2014 at 19:39:03 UTC, Andrei 
Alexandrescu wrote:
 On 9/13/14, 8:36 AM, bearophile wrote:
 This is a little Haskell program that uses the Maybe type 
 constructor:
[snip] As others noted, I think we need a kind of range with either zero or one element. Also, the range would have an "exception" property that returns null if the operation was successful (and the element is there) or whatever exception produced the result. E.g.: MaybeRange fun() { ... } ... auto r = fun; if (r.empty) { assert(r.exception); ... error case ... } else { ... use r.front ... r.popFront; assert(r.empty); // just one element } Andrei
The problem with that is this: making a hypothetical Option type a range encourages people to use it with the existing range algorithms. However, the second you use a map or filter on it, that exception property is no longer accessible. auto r2 = r.map!(val => val + 1); writeln(r2.exception); //Error So there is a need in Phobos for a flatMap (bind) function, and a flatten function. One problem with this is that it's going to get very annoying to add a .flatten after every chain of range operations on the Option type.
Sep 13 2014
prev sibling next sibling parent reply "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
On Saturday, 13 September 2014 at 19:39:03 UTC, Andrei 
Alexandrescu wrote:
 On 9/13/14, 8:36 AM, bearophile wrote:
 This is a little Haskell program that uses the Maybe type 
 constructor:
[snip] As others noted, I think we need a kind of range with either zero or one element. Also, the range would have an "exception" property that returns null if the operation was successful (and the element is there) or whatever exception produced the result. E.g.: MaybeRange fun() { ... } ... auto r = fun; if (r.empty) { assert(r.exception); ... error case ...
What if the operation failed without producing an exception? I.e., if we wrap an API that signals errors by returning false for example, do we really need to create an exception just to store it in `r.exception`?
 }
 else
 {
     ... use r.front ...
     r.popFront;
     assert(r.empty); // just one element
 }


 Andrei
Sep 14 2014
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/14/14, 6:17 AM, "Marc Schütz" <schuetzm gmx.net>" wrote:
 What if the operation failed without producing an exception? I.e., if we
 wrap an API that signals errors by returning false for example, do we
 really need to create an exception just to store it in `r.exception`?
UnspecifiedException
Sep 14 2014
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 09/14/2014 07:42 PM, Andrei Alexandrescu wrote:
 On 9/14/14, 6:17 AM, "Marc Schütz" <schuetzm gmx.net>" wrote:
 What if the operation failed without producing an exception? I.e., if we
 wrap an API that signals errors by returning false for example, do we
 really need to create an exception just to store it in `r.exception`?
UnspecifiedException
'Maybe' has traditionally denoted a type constructor which adds exactly one additional possible state to the underlying type, so this type that stores either a value or an exception should IMO be a separate construct.
Sep 14 2014
prev sibling parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
13-Sep-2014 23:39, Andrei Alexandrescu пишет:
 On 9/13/14, 8:36 AM, bearophile wrote:
 This is a little Haskell program that uses the Maybe type constructor:
[snip] As others noted, I think we need a kind of range with either zero or one element. Also, the range would have an "exception" property that returns null if the operation was successful (and the element is there) or whatever exception produced the result. E.g.:
I think it may be a bit too much to mix "exception or ok" and "1 or none" into a single type. Otherwise I agree. For precedents e.g. Scala has Option!T (or rather Option[T]) and Try[T] to denote Some!T or None, and Success!T or Failure(Throwable) respectively. And then uses composition to cover all of potential combinations.
 MaybeRange fun() { ... }
 ...
 auto r = fun;
 if (r.empty)
 {
      assert(r.exception);
      ... error case ...
 }
 else
 {
      ... use r.front ...
      r.popFront;
      assert(r.empty); // just one element
 }


 Andrei
-- Dmitry Olshansky
Sep 14 2014
parent "Dicebot" <public dicebot.lv> writes:
On Sunday, 14 September 2014 at 20:10:27 UTC, Dmitry Olshansky
wrote:
 13-Sep-2014 23:39, Andrei Alexandrescu пишет:
 On 9/13/14, 8:36 AM, bearophile wrote:
 This is a little Haskell program that uses the Maybe type 
 constructor:
[snip] As others noted, I think we need a kind of range with either zero or one element. Also, the range would have an "exception" property that returns null if the operation was successful (and the element is there) or whatever exception produced the result. E.g.:
I think it may be a bit too much to mix "exception or ok" and "1 or none" into a single type. Otherwise I agree. For precedents e.g. Scala has Option!T (or rather Option[T]) and Try[T] to denote Some!T or None, and Success!T or Failure(Throwable) respectively. And then uses composition to cover all of potential combinations.
I agree with Dmitry - mixing too many independent concepts into one entity will make it less widely usable and create false expectations. Better to keep such things independent.
Sep 17 2014
prev sibling parent =?UTF-8?B?Ik5vcmRsw7Z3Ig==?= <per.nordlow gmail.com> writes:
On Saturday, 13 September 2014 at 15:36:30 UTC, bearophile wrote:
 This is a little Haskell program that uses the Maybe type 
 constructor:


 foo :: Int -> Maybe Int
 foo x | x < 10 = Just x
 foo _          = Nothing

 main = do
     print $ foo 5
     print $ foo 15


 Its output:

 Just 5
 Nothing




 This is a similar D program, that uses Nullable:

 import std.stdio, std.typecons;

 Nullable!int foo(int x) {
     return (x < 10) ?
            typeof(return)(x) :
            typeof(return)();
 }

 void main() {
     writeln(foo(5));
     writeln(foo(15));
 }


 Its output:

 5
 core.exception.AssertError C:\dmd2\src\phobos\std\typecons.d(1515): 
 Called `get' on null Nullable!int.
 ...


 I think it's better for write(Nullable!int()) to not raise an 
 error, but to print something like a "<null>" etc.

 A bigger problem is in the usage of Nullable. I'd like the D 
 type system to be modified and improved to support Nullables 
 with a nicer syntax.

 Bye,
 bearophile
Further I would like rules for implicit conversion to bool of a new template Optional behave as: - null => false - otherwise => true This makes pattern-matching much more natural such as if (auto hit = context.tryMatch!T) // returns Optional!T { use_hit(hit); } else if (auto hit = context.tryNextRule!U) // returns Optional!U { use_hit(hit); } With D's lazy evaluation matchers can be chained. See for example my use of https://github.com/nordlow/justd/blob/master/algorithm_ex.d#L148 in my C++ demanger module (not quite complete) https://github.com/nordlow/justd/blob/master/mangling.d This will make the bool conversion semantics of Optional![T|U] as a return value in parsing/pattern-matching analogous with that of string.
Sep 14 2014