Hi, I'm working on an Optional!T type that is a mixture of Scala's Option[T] (i.e. range based) and Swift's and Kotlin's T? (i.e. safe dispatching). I'm interested in hearing about mutability concerns.

So I want operations on the optional to dispatch to the underlying type T if it's present. So let's take opUnary as an example, this is how it's currently implemented:

    auto opUnary(string op)() {
        return this.opUnaryImpl!op();
    }
    auto opUnary(string op)() const {
        return this.opUnaryImpl!(op, const(T))();
    }
    auto opUnary(string op)() immutable {
        return this.opUnaryImpl!(op, immutable(T))();
    }
    private auto opUnaryImpl(string op, U = T)() const {
        import std.traits: isPointer;
        static if (op == "*" && isPointer!U) {
            import std.traits: PointerTarget;
            alias P = PointerTarget!U;
return empty || front is null ? no!P : some(cast(P)*this._value);
        } else {
            if (empty) {
                return no!U;
            } else {
                return some(mixin(op ~ "cast(U)_value"));
            }
        }
    }

(functions "some" and "no" are type constructors which return an Optional!T of whatever the argument type is - except "no" needs an explicit T argument)

Why not "opUnary(string op)() inout"?

The reason it's like this is because I want to transfer the constness of "this" to the value T that is stored inside. If I rewrite "opUnaryImpl()() const" as "opUnary()() inout" and remove the implementation for mutable, const, and immutable, then this works:

immutable a = Optional!int(3);
++a;

And the internal value is modified.

Should that be allowed?

The caveat is that 1) I want Optional!T to be nogc compatible. So therefore the value is stored similarly to this PR in phobos [1] (also for an Optional type)

And 2) Optional!T provides an "unwrap" function that returns a T (if T is a class or interface), or a T*. So, if I allow modification by using inout on opUnary, then for the sake of consistency, I should be able to do this:

immutable a = Optional!int(3);
a = 4;

But I can't do this because Optional.opAssign would be either inout or immutable and I can't modify this.value = newValue;

And then what about:

auto a = Optional(immutable int)(3);
a = 3; // should this be allowed?

If it is allowed then this will fail because of the nogc requirement:

unittest {
    Optional!(immutable int) a = some!(immutable int)(5);
    immutable(int)* p = a.unwrap;
    assert(*p == 5);
    a = 4;
    assert(*a.unwrap == 4);
    assert(*p == 5);
}

Comments, suggestions, opinions?

Cheers,
- Ali

[1] https://github.com/dlang/phobos/pull/3915

Reply via email to