Is the other-kind-of-null really necessary in Nullable and Variant?

Idan Arye GenericNPC at gmail.com
Sun Apr 28 09:33:18 PDT 2013


When you use `std.typecons.Nullable` with a type that already 
accept `null` values, you get two types of nulls - the 
`Nullable`'s null state the the regular type's `null`:

     Nullable!string a;
     writeln(a.isNull()); //prints "true"
     a = null;
     writeln(a.isNull()); //prints "false"
     a.nullify();
     writeln(a.isNull()); //prints "true"

There is another version of  Nullable where instead of a boolean 
specifying if the value is null or not, you set a value to act as 
the null value. If we set that null value to D's `null`, we can 
get the previous example to work as expected:

     Nullable!(string, null) a;
     writeln(a.isNull()); //prints "true"
     a = null;
     writeln(a.isNull()); //prints "true"
     a.nullify();
     writeln(a.isNull()); //prints "true"

What I suggest is to check if the type passes to `Nullable` 
accepts `null`, and if so - alias it to the second template with 
`null` as it's null value.

As an added benefit, this will allow us to make null assignment 
to `Nullable` possible. The way Phobos is now it's tricky - if I 
write:
     Nullable!string a = null;
Should `a` be D's `null` or a nullified `Nullable`? This is too 
confusing, and a uniform null state would solve this conflict.


`std.variant.Variant` is more tricky:

     Variant a;
     Variant b = cast(string) null;
     Variant c = cast(Object) null;
     writeln(a == b); //prints "false"
     writeln(a == c); //prints "false"
     writeln(b == c); //prints "false"
     writeln(b.convertsTo!Object()); //prints "false"
     writeln(c.convertsTo!string()); //prints "false"
     writeln(a.convertsTo!string()); //throws VariantException

And even more surprising:

     writeln(c == c); //prints "false"

Although:

     writeln(a == a); //prints "true"
     writeln(b == b); //prints "true"

And even:

     Object o1=null;
     Object o2=null;
     writeln(o1 == o2); //prints "true"


Again, there is no reason to have all those different types of 
no-value - a null is a null is a null. a `Variant` should have a 
single null value, which is also the default value, and whenever 
it is assigned to `null` it should change back to that value 
without caring about the type. That also mean that a `Variant` 
storing a null value should implicitly convert to *any* type that 
accept `null`(when using `get`, `coerce` and `convertsTo`).


I can probably implement this myself, but I want to hear the 
community's opinion before I start hacking.


More information about the Digitalmars-d mailing list