optional icon indicating copy to clipboard operation
optional copied to clipboard

Assigning `OptionalChain!X` to an `Optional!X` compiles, but result is inconsistent between DMD versions

Open SimonN opened this issue 2 years ago • 0 comments

Tested with the current package optional 1.3.0, I haven't tested with older versions of package optional.

Reduced code example:

import std.stdio;
import optional;

class X {
    int number = 0;

    this(in int n) {
        number = n;
    }

    Optional!X maybeIncrement() {
        return Optional!X(new X(number + 1));
    }
}

void main() {
    Optional!X x = new X(7);
    x = x.oc.maybeIncrement();

    if (x.empty) {
        writeln("x is now empty.");
    } else {
        writeln("x now holds ", x.front.number, ".");
    }
}

This code behaves differently between DMD versions.

  • On DMD 2.100 and older (at least another year back from that), it prints: "x now holds 8."
  • On DMD 2.102.1 and newer (e.g., in the current DMD 2.103.1), it prints: "x is now empty."

I haven't used digger or manual reduction for DMD versions to pin it down further in between 2.100 and 2.102.1. I could reduce it further in theory, but I'd rather like to know if I should rely on this behavior in usercode at all -- I got bugs from it after a compiler upgrade after all.

The critical line is x = x.oc.maybeIncrement(); where

  • the left-hand side x is of type Optional!X for a class X, and
  • the right-hand side x.oc.maybeIncrement() is of type OptionalChain!X.

What is the desired behavior?

  1. x = x.oc.maybeIncrement; fails to compile.
  2. x is now a some(new X(8)), which I expected in usercode.
  3. x is now empty, which is the current behavior in DMD 2.102.1.

In the example, I've also tried x = x.oc.maybeIncrement().toOptional(); explicitly. This doesn't change the behavior at all: It still gives the exact same inconsistent result, i.e., some(new X(8)) on the older DMD versions, and empty on newer DMD versions.


Workaround: I've replaced lines such as x = x.oc.maybeIncrement(); with:

x = x.empty ? Optional!X() : x.front.maybeIncrement();

This behaves the same across all DMD versions, and would print in our example: "x now holds 8."

SimonN avatar May 26 '23 01:05 SimonN