Open question: what code pattern you use usually for null safety problem

ddcovery antoniocabreraperez at gmail.com
Fri Jan 15 16:42:20 UTC 2021


On Friday, 15 January 2021 at 14:19:35 UTC, Steven Schveighoffer 
wrote:
> On 1/14/21 7:27 PM, ddcovery wrote:
>> On Thursday, 14 January 2021 at 20:23:08 UTC, Steven 
>> Schveighoffer wrote:
>>>
>>> You could kinda automate it like:
>>>
>>> struct NullCheck(T)
>>> {
>>>    private T* _val;
>>>    auto opDispatch(string mem)() if (__traits(hasMember, T, 
>>> mem)) {
>>>        alias Ret = typeof(() { return __traits(getMember, 
>>> *_val, mem); }());
>>>        if(_val is null) return NullCheck!(Ret)(null);
>>>        else return NullCheck!(Ret)(__trats(getMember, *_val, 
>>> mem));
>>>    }
>>>
>>>    bool opCast(V: bool)() { return _val !is null; }
>>> }
>>>
>>> auto nullCheck(T)(T *val) { return AutoNullCheck!T(val);}
>>>
>>> // usage
>>> if(nullCheck(person).father.father && 
>>> person.father.father.name == "Peter")
>>>
>>> Probably doesn't work for many circumstances, and I'm sure I 
>>> messed something up.
>>>
>>> -Steve
>> 
>> I'm seeing "opDispatch" everywhere last days :-). It's really 
>> powerful!!!
>> 
>> If we define an special T _(){ return _val; } method, then you 
>> can write
>> 
>>    if( nullCheck(person).father.father.name._ == "Peter")
>> 
>> And renaming
>> 
>>    if( ns(person).father.father.name._ == "Peter" )
>
> This doesn't work, if person, person.father, or 
> person.father.father is null, because now you are dereferencing 
> null again.
>
> But something like this might work:
>
> NullCheck(T)
> {
>    ... // opdispatch and stuff
>    bool opEquals(auto ref T other) {
>       return _val is null ? false : *_val == other;
>    }
> }
>
> Something similar to BlackHole or WhiteHole. Essentially 
> there's a default action for null for all types/fields/methods, 
> and everything else is passed through.
>
> Swift has stuff like this built-in. But D might look better 
> because you wouldn't need a chain of question marks.
>
> -Steve

I don't know if I can add this to Dlang IDE and then share a 
link... links that I generate doesn't work...

* I have adapted the "onDispatch" and the factory method to 
manage nullable and not nullable values
* The unwrapper "T _()" method returns Nullable!T for nullable 
value types instead T  (similar to c#)

* I removed the T* when testing changes (I discovered after 1000 
changes that template errors are not well informed by the 
compiler... I losted a lot to discover a missing import)... I 
will try to restore.


import std.typecons;
import std.traits;

void main()
{
     Person person = new Person("Andres", 10, new Person("Peter", 
40, null));
     // null reference
     assert(ns(person).father.father._ is null);
     // null reference
     assert(ns(person).father.father.name._ is null);
     // reference value
     assert(ns(person).father.name._ == "Peter");
     // Nullable!int
     assert(ns(person).father.father.age._.isNull);
     assert(ns(person).father.father.age._.get(0) == 0);
     assert(ns(11)._.get == 11);
}

struct NullSafety(T)
{
     private T _val;
     private bool _isEmpty;

     auto opDispatch(string name)() if (__traits(hasMember, T, 
name))
     {
         alias Ret = typeof((() => __traits(getMember, _val, 
name))());
         if (_val is null)
         {
             static if (isAssignable!(Ret, typeof(null)))
                 return NullSafety!(Ret)(null, true);
             else
                 return NullSafety!(Ret)(Ret.init, true);
         }
         else
         {
             return NullSafety!(Ret)(__traits(getMember, _val, 
name), false);
         }
     }

     static if (isAssignable!(T, typeof(null))) // Reference types 
unwrapper
         T _()
         {
             return _val;
         }
     else // value types unwrapper
         Nullable!T _()
         {
             return _isEmpty ? Nullable!T() : Nullable!T(_val);
         }

}

auto ns(T)(T val)
{
     static if (isAssignable!(T, typeof(null)))
         return NullSafety!T(val, val is null);
     else
         return NullSafety!T(val, false);
}

class Person
{
     public string name;
     public Person father;
     public int age;
     this(string name, int age, Person father)
     {
         this.name = name;
         this.father = father;
         this.age = age;
     }
}


More information about the Digitalmars-d-learn mailing list