Consider the following code:

struct ArrayWrapper(T)
{
    T t;
        
    this(T t)
    {
        assert(t !is null);
    }

    @disable this(typeof(null));
        
    typeof(this) opAssign(T val)
    {
        assert(t !is null);
        this.t = val;

        return this;
    }
        
    @disable typeof(this) opAssign(typeof(null));
    @disable typeof(this) opAssign(typeof([]));
}

void main()
{
    //This is caught at compile time
    ArrayWrapper!(int[]) a = null;

    //This throwns a runtime error
    ArrayWrapper!(int[]) b = [];
}

That's fine, though, we can just add `@disable this(typeof([]))`. But wait, that doesn't work. The @disable'd constructor is ignored and it takes the this(T t) constructor instead. I have no idea why, as this(typeof(void[])) should be more specialized than this(int[]) when called with `[]`, but okay.

This isn't the only case that this doesn't work, either:

ArrayWrapper!(int[]) b;
//Caught at compile time, as expected
b = null;
//Throws a runtime error
b = [];

So in both cases, the compiler ignores the @disable'd constructor and opAssign when called with `[]`. I tried changing them both to be templated, which made the "normal" constructor and opAssign less specialized than the @disable'd ones. Fortunately, this strategy worked... sort of:

struct ArrayWrapper(T)
{
    T t;
        
    this(U)(U u)
    {
        assert(u !is null);
    }

    @disable this(typeof(null));
    @disable this(typeof([]));
        
    typeof(this) opAssign(U)(u val)
    {
        assert(u !is null);
        this.t = val;

        return this;
    }
        
    @disable typeof(this) opAssign(typeof(null));
    @disable typeof(this) opAssign(typeof([]));
}

void main()
{
    //This is caught at compile time
    ArrayWrapper!(int[]) a = null;

    //This is caught at compile time too now. Awesome!
    ArrayWrapper!(int[]) b = [];



    ArrayWrapper!(int[]) a;
    //Caught at compile time
    a = null;

    ArrayWrapper!(int[]) b;
    //Now also caught at compile time
    b = [];
}

My hopes were instantly dashed when I tried the following:

//Compile error. Okay...
ArrayWrapper!(void[]) c = [];

//This is also a compile error
c = cast(void[])[1, 2, 3];



And the same for opAssign:

ArrayWrapper!(void[]) c;
//Compile error
c = [];

//Also a compile error
c = cast(void[])[1, 2, 3];


So as you can see, it's more or less impossible to completely catch the assignment of [] to an array at compile time, even though it should be perfectly feasible. Is there any way I can accomplish this without making ArrayWrapper unusable for void[], or is a runtime check the best I can do?





Reply via email to