For the latest dmd, https://github.com/D-Programming-Language/dmd/commit/1193f7828b444056c943742daae0a5ccf262272e , I've implemented the ability to disable default initialization. This makes it practical to implement a library based "NotNull" type without a special syntax for it. The rationale for this is (rather than making it builtin) one can now build any type that is a restricted subset of another type. I suspect that a non-null type is just scratching the surface of this ability.

Here's a draft prototype of the NotNull type:

import std.c.stdio;

struct NotNull(P) if (is(typeof({P p = null;})))
{
    P p;

    this() @disable;

    this(P q)
    {
        assert(q);
        p = q;
    }

    NotNull opAssign(P q)
    {
        assert(q);
        p = q;
        return this;
    }

    alias p this;
}

void main()
{
    int x;
    NotNull!(int*) s = &x;
    *s = 3;
    printf("test1 %d\n", *s);
    s++;
    printf("test2 %d\n", s[-1]);
}

What it does is:
1. disallows instantiation with any type that null doesn't implicitly convert to
2. disables default construction (this is the new feature)
3. intercepts construction and assignment to enforce not-nullness
4. uses alias this to forward the rest to the wrapped pointer type

For example, try this:

void main()
{
    NotNull!(int*) s;
// Error: variable test.main.s initializer required for type NotNull!(int*)
}

I do think that the "this() @disable;" is an ugly syntax, and I cringe when seeing it. But I can't think of anything better. It does make logical sense given the existence of default construction syntax and the @disable, so in a sense it is just connecting existing dots, which has a compelling value.

Reply via email to