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

Idan Arye GenericNPC at gmail.com
Mon Apr 29 10:57:30 PDT 2013


On Monday, 29 April 2013 at 16:14:02 UTC, deadalnix wrote:
> 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.

The point is that you are forcing ref variables to point to data, 
even in paths where there is no data for them to point to.

Let's say we have something like:

     MyClass myObject;
     auto myVar1=DEFAULT_VALUE_FOR_MY_VAR_1;
     bool objectCreated=false;
     if(myCondition()){
         myObject=new MyClass(/*some arguments*/);
         objectCreated=true;
         myVar1=myObject.calculateSomething();
     }
     auto myVar2=calculateSomethingElse(myVar1);
     if(objectCreated){
         myObject.doSomething(myVar2);
     }
     doSomethingElse(myVar2);

It would be nice to create `myObject` in the second `if`, right 
before we use it, but this is not possible, since if 
`myCondition` is `true` and we do allocate `myObject`, we need to 
use it to calculate `myVar2`. And we can't pull the call for 
`myObject.doSomething` to the first `if` either - because we need 
to calculate `myVar2` before we use it. So, why not bring the 
calculation of `myVar2` into the first `if` as well? Because we 
need it for `doSomethingElse`, which should be invoked whether or 
not we allocate `myObject`!

As humans, we can easily see that if we didn't allocate 
`myObject` that will also mean that `objectCreated` remains 
false, and therefore the program will not enter the second `if`. 
I would like to see a data flow analysis mechanism that figures 
that out - and that's a simple case!

If `myObject` was `int` it would be easy - we could initialize it 
to `0` at declaration. But object references are not that simple 
- if you take away `null`, what will you init `myObject` to? 
Remember - it needs to be an instance of `MyClass` or of a 
subclass of `MyClass`. That means that:
a) You have to allocate memory for an object you will not use.
b) You need to call a constructor, that might have side-effects.
c) You end up with an object that has a meaningless state.

Now, let's look at that meaningless object we created. What if 
`MyClass` has fields which are object references themselves? They 
can't be in the "uninitialized state" - I would like to see the 
data flow analysis mechanism that can follow that! So, that means 
we need to set them to meaningless objects as well.

Now, consider implementing a linked list.


More information about the Digitalmars-d mailing list