Skip to content

Instantly share code, notes, and snippets.

@rikkimax
Created February 26, 2026 13:49
Show Gist options
  • Select an option

  • Save rikkimax/21242118e3bc1bf5f28024c2cdc33557 to your computer and use it in GitHub Desktop.

Select an option

Save rikkimax/21242118e3bc1bf5f28024c2cdc33557 to your computer and use it in GitHub Desktop.

opUnwrapIfTrue

Field Value
DIP: (number/id -- assigned by DIP Manager)
Author: Richard (Rikki) Andrew Cattermole
Implementation: dlang/dmd#22570
Status: Draft

Abstract

Adds a new operator overload that enables if statements to model checking for truthiness prior to getting a value. Similar to foreach statements supporting of ranges.

Contents

Rationale

In the authors codebase is a result type, with support for an error. It goes to an extreme extent to require a check for a given value of the result type to have been checked using opCast!bool, however this is very easy to miss when you do the get call which results in a runtime error. This was exhibited over many years period as being problematic.

In PhobosV2, Nullable had an alias this to its get method, this however proved to be heavily error prone and was removed.

To eliminate both these issues, the check must occur before the getter. With support for the else pathway when the check fails. Having it be language backed means it cannot be used wrongly.

Prior Work

The language supports foreach statements with range primitives, specifically empty, front, and back.

Rust and Swift both offer support with if statements for check and gets pairing in if statements;

let result: Option<i32> = Some(99);
if let Some(value) = result {
	// value is i32 variable
} else {
}
let result: Int? = 99
if let value = result {
} else {
}

Description

Add a new operator overload for structs: opUnwrapIfTrue.

This augments opCast!bool truthiness operator overload for structs, to allow unwrapping of a wrapped value in if statements.

Result!int result = ...;

if (int value = result) {
    // got a value!
} else {
    // oh noes an error or default init state
}

The current lowering with just the truthiness check looks like:

if (Result!int result2 = result, result2.opCast!bool) {
	scope(exit) result2.destroy;
	...
} else {
	result2.destroy;
}

This proposal further augments it to make it look like:

if (Result!int __temp = result, __temp.opCast!bool) {
	scope(exit) __temp.destroy;
	int value = __temp.opUnwrapIfTrue();
} else {
	__temp.destroy;
}

It does not use inference, you may use storage classes like auto instead of typing to the unwrapped value's type.

if (auto value = result)

Full example

The @mustuse is normative, it is optional to show its intended use-case.

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
}

Breaking Changes and Deprecations

No breaking changes will occur, this is an entirely opt-in feature.

Reference

Copyright & License

Copyright (c) 2026 by the D Language Foundation

Licensed under Creative Commons Zero 1.0

History

The DIP Manager will supplement this section with links to forum discsusionss and a summary of the formal assessment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment