On Sunday, 25 March 2018 at 23:00:11 UTC, Simen Kjærås wrote:
On Sunday, 25 March 2018 at 21:26:57 UTC, aliak wrote:
struct Optional(T) {
  Unqual!T value;
  opAssign(T t) {
    value = cast(Unqual!T)(t);
  }
}

Consider this case:

Optional!(immutable int) a = some(3);
immutable int* p = &a.value;
a = some(5);

Of course, if Optional offers no way to get a reference to the wrapped value (say, if a.value is an @property function that doesn't return ref T), then using Unqual internally is safe*.

Someone with knowledge of the internal layout of Optional might use tricks like *cast(immutable(int)*)&a, but in that case they're breaking the type system anyway, and one simply cannot negotiate with terrorists.

*actually, this may not be 100% true, in cases where T.opAssign does weird things. Consider:

struct Foo {
    int* p;

    void opAssign(Foo rhs) {
        p = rhs.p;
        (*p)++;
    }
}

unittest {
    immutable a = Foo(new int(3));
    assert(*a.p == 3); // Passes
    Optional!(immutable(Foo)) b;
    b = a;
    assert(*a.p == 3); // Fails
}

There actually is a workaround for this, using destroy() and move() instead of assignment. I'm unsure if there are other corner cases to consider.


--
  Simen

Reply via email to