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