| Field | Value |
|---|---|
| DIP: | (number/id -- assigned by DIP Manager) |
| Author: | Richard (Rikki) Andrew Cattermole |
| Implementation: | dlang/dmd#22570 |
| Status: | Draft |
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.
- Rationale
- Prior Work
- Description
- Breaking Changes and Deprecations
- Reference
- Copyright & License
- History
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.
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 {
}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)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
}No breaking changes will occur, this is an entirely opt-in feature.
- Bug 22279 – alias this in Nullable(T, T nullValue) causes Error in writeln
- Bug 22293 – Nullable should define opCast!bool
Copyright (c) 2026 by the D Language Foundation
Licensed under Creative Commons Zero 1.0
The DIP Manager will supplement this section with links to forum discsusionss and a summary of the formal assessment.