Search code examples
d

Appending to an array of Nullable types


If I try to append a Nullable struct to an array, I have to cast it, but not when I assign it to the array using an index. Is this a bug or is it supposed to work this way?

import std.typecons;

struct Foo {
    string s;
    int i;
}

void main() {
    f1();
    f2();
    f3();
}

void f1() {
    auto foos = new Nullable!Foo[](10);
    foos[0] = Foo("abc", 10);  // OK
}

void f2() {
    Nullable!Foo[] foos;
    foos ~= Foo("abc", 10); // Error: cannot append type Foo to type Nullable!(Foo)[]
}    

void f3() {
    Nullable!Foo[] foos;
    foos ~= cast(Nullable!Foo)Foo("abc", 10);  // OK
}

Solution

  • That's intentional, though I'd say not ideal. D lacks implicit construction (except in one really obscure case, variadic class functions if you're curious) and what you're asking for there is implicit construction of the Nullable - given the Foo, you want to build a Nullable wrapper around it, and D doesn't let you do that without some kind of explicit action, either a director constructor call or a function call that acts like one* (in some user-defined arrays, an overloaded concat operator will do the construction for you, but you are using a built-in array so it is not overloaded at all).

    If you assign it, it calls Nullable!T.opAssign on the already-constructed item; an overloaded function implemented in the type http://dpldocs.info/experimental-docs/std.typecons.Nullable.opAssign.html which replaces the contents.

    But concatenation means a new element needs to be made, which hits this construction rule.

    I say it is not ideal because I so wish D had this feature. C++ had bad experiences with implicit constructors, but that's because ALL C++ constructors were implicit by default, unless you used the explicit keyword explicitly. D avoided that mistake, but threw the baby out with the bathwater :(

    Casting a value v to a struct S, when value is not a struct of the same type, is equivalent to:

    S(v)