Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow oc on const(Optional!X), allow frontOr within const nothrow @nogc #57

Open
SimonN opened this issue Apr 21, 2023 · 1 comment
Open

Comments

@SimonN
Copy link
Contributor

SimonN commented Apr 21, 2023

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:

  1. We can't call .oc.foo on a const Optional!X.
  2. We can't call frontOr within nothrow or @nogc, or on a const 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:

  1. We don't modify x by maybe calling the const method foo() on (presumably) a const(X) through the const(Optional!X).
  2. We don't modify x.oc.foo by calling .frontOr(3) because we merely have to examine the range x.oc.foo for emptiness and possibly take its front element. We never have to advance this range. Only if we were to call .popFront on a range, the range struct would have to be mutable, but .frontOr(3) should never call .popFront on any range.
  3. We provide a default value for frontOr without calling anything that throws, therefore frontOr will never throw.
  4. Since frontOr never 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;
}
@SimonN SimonN changed the title Allow oc on const(Optional!X), make frontOr const nothrow @nogc Allow oc on const(Optional!X), allow frontOr within const nothrow @nogc Apr 21, 2023
@aliak00
Copy link
Owner

aliak00 commented Apr 26, 2023 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants