First Draft: opUnwrapIfTrue

Dejan Lekic dejan.lekic at gmail.com
Mon Sep 21 18:54:44 UTC 2026


On Thursday, 26 February 2026 at 13:53:41 UTC, Richard (Rikki) 
Andrew Cattermole wrote:
> The DIP: 
> https://gist.github.com/rikkimax/21242118e3bc1bf5f28024c2cdc33557
>
> A new operator overload to allow if statements to automatically 
> unwrap result types and ensure that the check is called prior 
> to, similar to foreach statements support of ranges.
>
> This solves a prolific issue that I have had to deal with 
> result types and has been exhibited by ``Nullable`` in PhobosV2.
>
> Full example:
>
> ```d
> import core.attribute : mustuse;
>
> @mustuse
> struct Result(Type) {
>     private {
>         Type value;
>         bool haveValue;
>     }
>
>     this(Type value) {
>         this.value = value;
>         this.haveValue = true;
>     }
>
>     bool opCast(T:bool)() => haveValue;
>
>     Type opUnwrapIfTrue() {
>         assert(haveValue);
>         return value;
>     }
> }
>
> Result!int result = Result!int(99);
>
> if (int value = result) {
>     // got a value!
>     assert(value == 99);
> } else {
>     // oh noes an error or default init state
> }
> ```

I know I am late in this discussion - almost always want error 
why use `if` for something that is clearly for error handling.

I would rather have something like:
```
Result!int result = Result!int(99) or {
       /* error handling here where `error` just like `this` refers
          too the error object */
    }
```

I do understand that you guys want to use existing language 
primitives everywhere but if I need to use `if` then I would 
simply go with the usual if (result.ok) {} else { /* use 
result.error() to  get error object out of Result!(Error, 
ResultValue) */ } or match. Here is an example how it is done in 
ddn.result module:

```d
import ddn.result : Result, Success;

struct ParseError { string msg; size_t offset; }
struct Config { int value; }
struct UpdateError { enum Reason { NOT_FOUND, LOCKED } Reason 
reason; }

alias ParseResult = Result!(ParseError, Config);
alias UpdateResult = Result!UpdateError;

ParseResult parseConfig(scope const(char)[] text) {
    if (text.empty)
       return ParseResult(ParseError("empty input", 0));
    return ParseResult(Config(1));
}

// Caller-side handling:
auto result = parseConfig("");
if (result.ok()) {
    auto config = result.value();
} else {
    auto failure = result.error();
}
```

( `result.match()` works too ofc )

Full implementation is here: 
https://codeberg.org/ddn/ddn/src/branch/main/src/ddn/result.d

I am glad someone is working on this - it was about the time. But 
let's please do it right... My module above is far from best, but 
if I had a better one I would have used it. That is what I hope 
here. :)


More information about the dip.development mailing list