Null-Coalescing Operator and Extensions
Simen Kjærås
simen.kjaras at gmail.com
Tue Aug 28 13:27:28 UTC 2018
On Monday, 27 August 2018 at 14:59:20 UTC, SG wrote:
> On Monday, 27 August 2018 at 07:59:17 UTC, Simen Kjærås wrote:
>> That's the null propagation operator (?.). What SG asked for
>> is the null-coalescing operator (??). Of course, this can also
>> be implemented in D (albeit with a slight more horrible
>> syntax):
>
> Exactly, and I know it is an example, but it doesn't work for
> Variant.
>
> I was trying something like below, I need to find a way to test
> for all Nullable types out there, right now only works for
> Nullable!int.
Sadly, Variant's operator overloading is problematic - there
seems to be no way to write a struct such that its operator
overloading is preferred over Variant's, and Variant's fails to
compile. (issue 19200:
https://issues.dlang.org/show_bug.cgi?id=19200)
Once that issue has been fixed, this should work:
// Support aliak's optional, if available:
static if (__traits(compiles, {import optional;})) import
optional;
struct NullCoalesce {
static auto opBinaryRight(string op : "|", T)(T lhs) {
return NullCoalesceImpl!T(lhs);
}
}
struct NullCoalesceImpl(T) {
T value;
auto opBinary(string op : "|", R)(lazy R rhs) {
static if (is(typeof(value.peek!R))) {
if (auto tmp = value.peek!R)
return *tmp;
} else static if (is(typeof(value.isNull))) {
if (!value.isNull)
return value.get;
} else static if (is(typeof(value.unwrap))) {
if (auto tmp = value.unwrap)
return *tmp;
} else static if (is(typeof(value == null))) {
if (value != null)
return value;
} else {
static assert(false, "Cannot perform null-coalescing
on non-nullable type "~T.stringof~".");
}
return rhs;
}
}
alias NullCoalesce _;
unittest {
import std.variant;
import std.typecons;
int* a = null;
auto b = new int;
assert((a |_| b) == b);
a = new int;
assert((a |_| b) == a);
Variant c;
assert((c |_| 3) == 3);
c = 4;
assert((c |_| 3) == 4);
Nullable!int d;
assert((d |_| 3) == 3);
d = 4;
assert((d |_| 3) == 4);
static if (is(typeof(Optional!int))) {
Optional!int e;
assert((e |_| 3) == 3);
e = 4;
assert((e |_| 3) == 4);
}
}
Now, as has been pointed out, that only work for null-coalescing,
not null-propagation. It seems writers of Optional, Variant,
SumType, and so on, have decided not to support this out of the
box, but rather wrap it separately, like Basile B.'s
SafeAccess[1] and aliak's dispatch[2]. There's no real obstacle
to wrapping member access directly in Optional!T such that it
always return a Optional!(typeof(member)), though.
I've written an Optional somewhere that does safe access out of
the box, but it seems to be on my work computer, not this one.
--
Simen
[1]:
https://github.com/BBasile/iz/blob/master/import/iz/sugar.d#L1658
[2]: https://code.dlang.org/packages/optional
More information about the Digitalmars-d-learn
mailing list