-
Notifications
You must be signed in to change notification settings - Fork 8
Description
Using optional 1.3.0.
The following code works with no problems.
import optional;
class X {
int foo() const pure nothrow @safe @nogc {
return 5;
}
}
class Y {
Optional!X x;
int bar() pure @safe {
return x.oc.foo.frontOr(3);
}
}
This compiles fine.
The problem arises when we want to annotate bar() not only as pure @safe, but as const pure nothrow @safe @nogc in the same way as we did with foo(). If we add all those annotations to bar(), we get these errors:
- We can't call
.oc.fooon aconst Optional!X. - We can't call
frontOrwithinnothrowor@nogc, or on aconst OptionalChain!int. The exact static assert is: "Unable to call frontOr on type const(OptionalChain!int). It has to either be an input range, a Nullable!T, or an Optional!T".
In theory, i.e., without looking at the implementation of the optional library, these extra annotations comply with D's type system:
- We don't modify
xby maybe calling theconstmethodfoo()on (presumably) aconst(X)through theconst(Optional!X). - We don't modify
x.oc.fooby calling.frontOr(3)because we merely have to examine the rangex.oc.foofor emptiness and possibly take its front element. We never have to advance this range. Only if we were to call.popFronton a range, the range struct would have to be mutable, but.frontOr(3)should never call.popFronton any range. - We provide a default value for
frontOrwithout calling anything that throws, thereforefrontOrwill never throw. - Since
frontOrnever throws, it will never allocate with the GC.
We can argue that this report should be split into two separate issues: 1. oc should work on a const(Optional!X) and 2. frontOr should infer that it will neither modify, throw, nor allocate, given its usage with a default value like in our example. But I filed them together because they're so closely related, and because above example code is more meaningful when it shows both.
Do you see conceptual difficulties in allowing x.oc.foo.frontOr(3) from within a method annotated const pure nothrow @safe @nogc?
For now, I've rewritten the example as:
int bar() const pure nothrow @safe @nogc {
return x.empty ? 3 : x.front.foo;
}