Skip to content

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

@SimonN

Description

@SimonN

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."

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions