Jump to page: 1 2
Thread overview
Is the other-kind-of-null really necessary in Nullable and Variant?
Apr 28, 2013
Idan Arye
Apr 28, 2013
bearophile
Apr 28, 2013
Idan Arye
Apr 28, 2013
Jesse Phillips
Apr 29, 2013
deadalnix
Apr 29, 2013
Idan Arye
Apr 29, 2013
Simen Kjaeraas
Apr 29, 2013
Idan Arye
Apr 29, 2013
deadalnix
Apr 29, 2013
Idan Arye
Apr 29, 2013
Simen Kjaeraas
Apr 29, 2013
Idan Arye
Apr 29, 2013
Idan Arye
Apr 29, 2013
Simen Kjaeraas
Apr 29, 2013
deadalnix
April 28, 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.
April 28, 2013
Idan Arye:

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

Originally D dynamic arrays were almost conflated with regular pointers (they were seen as fat pointers). This was recently partially fixed (so assigning a pointer to a dynamic array is now forbidden), but accepting "null" for their empty literal is one left part of that original suboptimal design.

Time ago I have proposed to forbid "null" as literal for an empty dynamic array literal, an empty associative literal, or an empty string, and to accept only []  ""  [:] (D already has the first two literals and the third looks natural).

See also:
http://d.puremagic.com/issues/show_bug.cgi?id=3889
http://d.puremagic.com/issues/show_bug.cgi?id=5788
http://d.puremagic.com/issues/show_bug.cgi?id=7227

Bye,
bearophile
April 28, 2013
On Sunday, 28 April 2013 at 16:33:19 UTC, Idan Arye wrote:
> I can probably implement this myself, but I want to hear the community's opinion before I start hacking.

I would like to see the non-null null value to be removed.

I believe there is an improved variant somewhere, which may or may not do something with this.
April 28, 2013
On Sunday, 28 April 2013 at 17:02:57 UTC, bearophile wrote:
> Idan Arye:
>
>> 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"
>
> Originally D dynamic arrays were almost conflated with regular pointers (they were seen as fat pointers). This was recently partially fixed (so assigning a pointer to a dynamic array is now forbidden), but accepting "null" for their empty literal is one left part of that original suboptimal design.
>
> Time ago I have proposed to forbid "null" as literal for an empty dynamic array literal, an empty associative literal, or an empty string, and to accept only []  ""  [:] (D already has the first two literals and the third looks natural).
>
> See also:
> http://d.puremagic.com/issues/show_bug.cgi?id=3889
> http://d.puremagic.com/issues/show_bug.cgi?id=5788
> http://d.puremagic.com/issues/show_bug.cgi?id=7227
>
> Bye,
> bearophile

I used `Nullable!string` for the example, but it could just as easily be `Nullable!Object` or `Nullable!(int*)`.
April 29, 2013
On Sunday, 28 April 2013 at 16:33:19 UTC, Idan Arye wrote:
> 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"
>

All types should be non nullable. Problem solved.
April 29, 2013
On Monday, 29 April 2013 at 12:23:04 UTC, deadalnix wrote:
> On Sunday, 28 April 2013 at 16:33:19 UTC, Idan Arye wrote:
>> 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"
>>
>
> All types should be non nullable. Problem solved.

*All* types? Even object references and pointers?
April 29, 2013
On 2013-04-29, 17:34, Idan Arye wrote:

> On Monday, 29 April 2013 at 12:23:04 UTC, deadalnix wrote:
>> On Sunday, 28 April 2013 at 16:33:19 UTC, Idan Arye wrote:
>>> 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"
>>>
>>
>> All types should be non nullable. Problem solved.
>
> *All* types? Even object references and pointers?

That would be nice, yes.

-- 
Simen
April 29, 2013
On Monday, 29 April 2013 at 15:39:47 UTC, Simen Kjaeraas wrote:
> On 2013-04-29, 17:34, Idan Arye wrote:
>
>> On Monday, 29 April 2013 at 12:23:04 UTC, deadalnix wrote:
>>> On Sunday, 28 April 2013 at 16:33:19 UTC, Idan Arye wrote:
>>>> 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"
>>>>
>>>
>>> All types should be non nullable. Problem solved.
>>
>> *All* types? Even object references and pointers?
>
> That would be nice, yes.

And what would they be initialized to? When you write:
    Object obj;
what will `obj` refer to?

Also, what about the C&C++ interface? Without null values, how can you use an extern function that accepts or returns pointers?
April 29, 2013
On Monday, 29 April 2013 at 15:34:30 UTC, Idan Arye wrote:
> On Monday, 29 April 2013 at 12:23:04 UTC, deadalnix wrote:
>> On Sunday, 28 April 2013 at 16:33:19 UTC, Idan Arye wrote:
>>> 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"
>>>
>>
>> All types should be non nullable. Problem solved.
>
> *All* types? Even object references and pointers?

Especially object references and pointers.
April 29, 2013
On Monday, 29 April 2013 at 16:02:11 UTC, Idan Arye wrote:
> On Monday, 29 April 2013 at 15:39:47 UTC, Simen Kjaeraas wrote:
>> On 2013-04-29, 17:34, Idan Arye wrote:
>>
>>> On Monday, 29 April 2013 at 12:23:04 UTC, deadalnix wrote:
>>>> On Sunday, 28 April 2013 at 16:33:19 UTC, Idan Arye wrote:
>>>>> 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"
>>>>>
>>>>
>>>> All types should be non nullable. Problem solved.
>>>
>>> *All* types? Even object references and pointers?
>>
>> That would be nice, yes.
>
> And what would they be initialized to? When you write:
>     Object obj;
> what will `obj` refer to?
>
> Also, what about the C&C++ interface? Without null values, how can you use an extern function that accepts or returns pointers?

Data flow analysis can smash your face if you try to use that before initializing it. In fact, this is already done in many languages.
« First   ‹ Prev
1 2