D - Unsafe and doomed

Organic Farmer x at x.de
Sun Jan 5 23:32:28 PST 2014


On Saturday, 4 January 2014 at 22:08:59 UTC, Andrej Mitrovic 
wrote:
> On 1/4/14, Adam D. Ruppe <destructionator at gmail.com> wrote:
>> The big thing people have asked for before is
>>
>> Object foo;
>> if(auto obj = checkNull(foo)) {
>>     obj == NotNull!Object
>> } else {
>>    // foo is null
>> }
>>
>> and i haven't figured that out yet...
>
> Here you go:
>
> -----
> import std.stdio;
>
> struct NotNull(T) { T obj; }
>
> struct CheckNull(T)
> {
>     private T _payload;
>
>     auto opCast(X = bool)() { return _payload !is null; }
>
>     @property NotNull!T getNotNull() { return 
> NotNull!T(_payload); }
>     alias getNotNull this;
> }
>
> CheckNull!T checkNull(T)(T obj)
> {
>     return CheckNull!T(obj);
> }
>
> class C { }
>
> void main()
> {
>     Object foo;
>     if (auto obj = checkNull(foo))
>     {
>         writeln("foo is not null");
>     }
>     else
>     {
>         writeln("foo is null");
>     }
>
>     foo = new C;
>
>     if (auto obj = checkNull(foo))
>     {
>         // note: ":" rather than "==" due to alias this.
>         static assert(is(typeof(obj) : NotNull!Object));
>
>         // assignment will work of course (alias this)
>         NotNull!Object obj2 = obj;
>
>         writeln("foo is not null");
>     }
>     else
>     {
>         writeln("foo is null");
>     }
> }
> -----


Excuse me, not so fast ...

1. static assert asserts at compile time, so let's not put it in 
a runtime check of obj (converted to bool).

2.
     Object foo;
     assert(foo is null);
     NotNull!Object test = NotNull!Object(foo);
     assert(is(typeof(test) : NotNull!Object));
     static assert(is(typeof(test) : NotNull!Object));

always passes for a null reference, with or without static, as it 
should. So what good is NotNull?

3. To wit: if you replace main with

void main() {
     Object foo;

     auto obj = checkNull(foo);
     if (obj) {
         static assert(is(typeof(obj) : NotNull!Object)); //let's 
leave this inside the dynamic if, just to demonstrate (yuck!)
         assert(is(typeof(obj) : NotNull!Object));
         NotNull!Object obj2 = obj;
         writeln("foo is not null");
     } else {
         static assert(is(typeof(obj) : NotNull!Object));
         assert(is(typeof(obj) : NotNull!Object));
         writeln("foo is null");
     }

     foo = new C;

     obj = checkNull(foo);
     if (obj) {
         static assert(is(typeof(obj) : NotNull!Object));
         assert(is(typeof(obj) : NotNull!Object));
         NotNull!Object obj2 = obj;
         writeln("foo is not null");
     } else {
         static assert(is(typeof(obj) : NotNull!Object));
         assert(is(typeof(obj) : NotNull!Object));
         writeln("foo is null");
     }
}

all asserts pass, be they static or dynamic. The output is 
correct as in the original, but it has nothing to do with obj 
being convertible to NotNull!Object or not. It always is. The 
output is correct due to the simple runtime check whether obj is 
null or not.

Greets.
(PS: I think I just poked me in the eye with my pencil.)


More information about the Digitalmars-d mailing list