February 04, 2014
On 2/4/14, 12:32 AM, deadalnix wrote:
> On Tuesday, 4 February 2014 at 06:49:57 UTC, Andrei Alexandrescu wrote:
>>> That would be awesome. The breakage involved, is quite high however.
>>
>> No breakage if the opt-in flag is not used.
>>
>> Andrei
>
> OK, If you are willing to do that change, I'm 200% behind !
>
> Question, why do you propose to use @nullable instead of Nullable!T ?

Because it will be inferred locally, and we have precedent for that with attributes but not with type constructors.

Andrei

February 04, 2014
On Tuesday, 4 February 2014 at 13:44:00 UTC, Idan Arye wrote:
> On Tuesday, 4 February 2014 at 13:20:12 UTC, Dicebot wrote:
>> On Tuesday, 4 February 2014 at 13:11:49 UTC, Idan Arye wrote:
>>> Why is `bar(w);` an error? I may be perfectly valid for `bar` to accept null as argument.
>>
>> It should declare its argument as Nullable!w then.
>
> If non-null-by-default will be implemented that code will crash on the first line `Widget w = null;`. I was not talking about that - I was talking about the static analysis deadalnix demonstrated in the comments of that code.

Dicebot is right.
February 04, 2014
On Tuesday, 4 February 2014 at 14:54:35 UTC, Adam D. Ruppe wrote:
> This gives us:
>
> * Implementation help - no binary cost for Nullable!Object since it just uses null directly instead of a bool isNull field (the optimizer also knows this)
>

static if(isReferenceType!T) {
    union {
        T t;
        typeof(null) __;
    }
}

> * Consistency with all other types. Nullable!int works, Nullable!Object can be passed to a template, inspected, etc. without new traits for isNullable and everything.
>

I'm not sure I understand that.

> * Library functionality so we can also make other types that do the same kind of thing
>

I'm really confused now. What are you defending ??

> Then, if we did the Type? syntax, it would just be rewritten into Nullable!Type. Nullable's definition would probably be in the auto-imported object.d so it always works.

??????
February 04, 2014
On 2/4/14, 6:54 AM, Adam D. Ruppe wrote:
> On Tuesday, 4 February 2014 at 14:34:49 UTC, Idan Arye wrote:
>> Probably because `Nullable!` suggests that's it's a library solution -
>> and it isn't.
>
> It should be. The way I'd do it is
>
> Object o; // not null
> @nullable Object o; // like we have today
>
> BUT, user code would never use that. Instead, we'd have:
>
> struct Nullable(T) if(__traits(compiles, (@nullable T) {}) {
>     @nullable T;
> }

Yah, that's what I have in mind.

Andrei

February 04, 2014
On Tuesday, 4 February 2014 at 14:54:35 UTC, Adam D. Ruppe wrote:
> On Tuesday, 4 February 2014 at 14:34:49 UTC, Idan Arye wrote:
>> Probably because `Nullable!` suggests that's it's a library solution - and it isn't.
>
> It should be. The way I'd do it is
>
> Object o; // not null
> @nullable Object o; // like we have today
>
> BUT, user code would never use that. Instead, we'd have:
>
> struct Nullable(T) if(__traits(compiles, (@nullable T) {}) {
>    @nullable T;
> }
>
> // and a corresponding one so stuff like Nullable!int works
>
>
> This gives us:
>
> * Implementation help - no binary cost for Nullable!Object since it just uses null directly instead of a bool isNull field (the optimizer also knows this)
>
> * Consistency with all other types. Nullable!int works, Nullable!Object can be passed to a template, inspected, etc. without new traits for isNullable and everything.
>
> * Library functionality so we can also make other types that do the same kind of thing
>
>
> Then, if we did the Type? syntax, it would just be rewritten into Nullable!Type. Nullable's definition would probably be in the auto-imported object.d so it always works.

So what you are saying is that it should be implemented in the core language(`@nullable`), and than wrapped in the standard library(`Nullable!`) so we can have the benefit of using D's and Phobos' rich template-handling functionality?

Sounds good, but the only problem is that the `@nullable` syntax looks too clean - cleaner than `Nullable!`. That will mean that some people will prefer it - enough to break all the benefits of using the template.

I think the core language implementation should look more ugly and cumbersome. How about `__traits(nullable, T)`? People already know that traits are better used via wrappers whenever possible - in contrast to attributes that are meant to be used directly.
February 05, 2014
On Tuesday, 4 February 2014 at 18:26:10 UTC, deadalnix wrote:
> static if(isReferenceType!T) {
>     union {
>         T t;
>         typeof(null) __;
>     }
> }

cool, that would work. @nullable is now totally dead to me.

>> * Consistency with all other types. Nullable!int works, Nullable!Object can be passed to a template, inspected, etc. without new traits for isNullable and everything.
>>
>
> I'm not sure I understand that.

"@nullable int" wouldn't work. A nullable int needs a separate field to store if it has a value or not, since int == 0 is a valid payload.

A Nullable!T template can store the separate field if needed (use static if to add the field or use the union with typeof(null)) and thus work for all types with uniform user-side API.

> I'm really confused now. What are you defending ??

Built-in references become not-null by default. Library type Nullable!T is used when yo need null.
February 05, 2014
On Tuesday, 4 February 2014 at 22:57:06 UTC, Idan Arye wrote:
> So what you are saying is that it should be implemented in the core language(`@nullable`), and than wrapped in the standard library(`Nullable!`) so we can have the benefit of using D's and Phobos' rich template-handling functionality?

That was my first thought but deadalnix mentioned a union with typeof(null) which would achieve the same thing.

so I think @nullable is useless and we should just focus on the library type Nullable!T.

There's lastly the question of

if(nullable_ref) {
  // nullable_ref is implicitly converted to not null
}

and meh, as far as I'm concerned, this is already a solved problem:

if(auto not_null = nullable_ref) {
   // use not_null
}


But if we wanted the same name's type to magically change, I'd prefer to add some kind of operator overloading to hook that in the library too. Just spitballing syntax but

struct Nullable(T) {
    static if(__traits(potentiallyNullable, T)) {
       union {
          T payload;
          typeof(null) _;
       }
       alias payload if;
    } else {
       struct {
         T payload;
         bool isNull;
       }
       T helper(out bool isValid) {
            isValid = isNull;
            return payload;
       }
       alias helper if;
    }
    /* other appropriate overloads/methods */
}


The last line is the magic. Unlike the existing technique, opCast(T:bool)() {}, it would allow changing types inside the if.

Note that something can be done right now using opCast, a helper type, and alias this: http://arsdnet.net/dcode/notnullsimplified.d see checkNull (thanks to Andrej Mitrovic for showing this to me)

So I'm generally meh on it, but if we do want to do magic changing types, I definitely want it available in the library for more than just nullability.
February 05, 2014
On Tuesday, 4 February 2014 at 16:00:20 UTC, Meta wrote:
> I'm interested in how this might fit in with your recent discovery in this thread:
>
> http://forum.dlang.org/thread/majnjuhxdefjuqjlpbmv@forum.dlang.org?page=1

There's a lot of potential for pluggable semantic checks with that. Earlier today, I toyed with it for checking virtual functions:

import core.config;
class Foo {
        @virtual void virt() {} /// annotated so OK
        void oops() {} // not annotated, yet virtual, we want a warning
}


module core.config;

string[] types;

template TypeCheck(T) {
        static if(is(T == class))
                enum lol = virtualCheck!T();
}

enum virtual;

bool virtualCheck(T)() {
        foreach(member; __traits(derivedMembers, T)) {
                static if(__traits(isVirtualFunction, __traits(getMember, T, member))) {
                        static if(__traits(getAttributes, __traits(getMember, T, member)).    length == 0)
                        pragma(msg, "Warning " ~ T.stringof ~ "." ~ member ~ " is virtual");
                }
        }
        return true;
}


Warning: Foo.oops is virtual




A similar thing could be set up for nullable, or maybe even borrowed (though it would fall short there without the help of the scope storage class on parameters and return values).


It'd scan all the types and if not explicitly marked nullable or NotNull, it can throw a static assert or pragma(msg).

But RtInfo can't see local variables nor module-level free functions, so it can't do a complete check. I'd love a "RTInfo for modules" (enhancement in bugzilla already) and a way to inspect local varaibles with __traits somehow too...



Anyway, bottom line is rtinfo can help add some of these semantics but wouldn't go all the way. Going all the way will break code, but I think it will be worth it. Breakage in general is wrong, but when it helps find latent bugs and is relatively easy to deal with (adding Nullable! or GC! in appropriate places) the benefits may be worth the cost. I believe that's the case here.
February 05, 2014
On Wednesday, 5 February 2014 at 03:12:57 UTC, Adam D. Ruppe wrote:
> On Tuesday, 4 February 2014 at 22:57:06 UTC, Idan Arye wrote:
>> So what you are saying is that it should be implemented in the core language(`@nullable`), and than wrapped in the standard library(`Nullable!`) so we can have the benefit of using D's and Phobos' rich template-handling functionality?
>
> That was my first thought but deadalnix mentioned a union with typeof(null) which would achieve the same thing.
>
> so I think @nullable is useless and we should just focus on the library type Nullable!T.
>
> There's lastly the question of
>
> if(nullable_ref) {
>   // nullable_ref is implicitly converted to not null
> }
>
> and meh, as far as I'm concerned, this is already a solved problem:
>
> if(auto not_null = nullable_ref) {
>    // use not_null
> }
>
>
> But if we wanted the same name's type to magically change, I'd prefer to add some kind of operator overloading to hook that in the library too. Just spitballing syntax but
>
> struct Nullable(T) {
>     static if(__traits(potentiallyNullable, T)) {
>        union {
>           T payload;
>           typeof(null) _;
>        }
>        alias payload if;
>     } else {
>        struct {
>          T payload;
>          bool isNull;
>        }
>        T helper(out bool isValid) {
>             isValid = isNull;
>             return payload;
>        }
>        alias helper if;
>     }
>     /* other appropriate overloads/methods */
> }
>
>
> The last line is the magic. Unlike the existing technique, opCast(T:bool)() {}, it would allow changing types inside the if.
>
> Note that something can be done right now using opCast, a helper type, and alias this: http://arsdnet.net/dcode/notnullsimplified.d see checkNull (thanks to Andrej Mitrovic for showing this to me)
>
> So I'm generally meh on it, but if we do want to do magic changing types, I definitely want it available in the library for more than just nullability.

The question is - will the optimizer be able to handle this as good as it could handle a built-in `@nullable`? If so - I'm all for it, but if not - D is still a system language and performance still counts.

Anyways, the order in the union should be reversed:

    union {
        typeof(null) _;
        T payload;
    }

The first field of the union is the one who gets initialized. If `T` is the first union "field", depending on how non-null-by-default will be implemented either an object of type `T` will be implicitly constructed or compilation will break when a nullable is created without initializing a value. If `typeof(null)` is the first union "field" it'll be initialized to `null` - as everyone should expect.
February 05, 2014
On 2014-02-03 11:41, Jonathan M Davis wrote:

> I recall there being a change to druntime such that it would print a backtrace
> for you if you hit a segfault, but it doesn't seem to work when I write a
> quick test program which segfaults, so I'm not sure what happened to that.

1. It only works on Linux
2. You need to call a function in a module constructor (I don't recall which one)

-- 
/Jacob Carlborg