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.

Reply via email to