Re: Is there a simple way to check if value is null for every case?
On Monday, 27 August 2018 at 21:48:04 UTC, Alex wrote: On Monday, 27 August 2018 at 19:36:29 UTC, aliak wrote: Then Nullable!(int*) would be the same as int*. Or even better maybe is to give a compiler error when you try and stuff a nullable type inside a Nullable. Because ... why? Isn't it arguable, whether this is desired? I mean, in the present state you can separate the cases, whether the Nullable is set or not. This is a feature. If Nullable!(int*) behaves like int*, it would be somewhat more straight forward, which is maybe also a feature. But you loose something you can do right now... Certainly arguable :) I'm unsure about of what you lose is worth having, is the problem. And I have trouble thinking of a use case? If we implement opEquals(typeof(null)) as is now, then this code: Nullable!(int*) n = null; assert(n != null); passes. And if we have no opEquals then we can't test for native null on a 'null'able type O_o Another options is: bool opEquals(typeof(null)) { enum isNullInvalid = is(T == class) || is(T == interface) || isSomeFunction!T; static if (isNullInvalid) return isNull || data is null else return isNull; } I also did a quick search on google "allintext: "nullable" site:github.com filetype:d" and there were 0 instances of T* (just looked thorugh search results didn't click in).
Re: tupleof function parameters?
On Tuesday, 28 August 2018 at 06:11:35 UTC, Jon Degenhardt wrote: The goal is to write the argument list once and use it to create both the function and the Tuple alias. That way I could create a large number of these function / arglist tuple pairs with less brittleness. --Jon I would probably use a combination of std.traits.Parameters and std.traits.ParameterIdentifierTuple. Parameters returns a tuple of types and ParameterIdentifierTuple returns a tuple of strings. Maybe you'll need to implement a staticZip to interleave both tuples to get the result you want. (although I remember seeing one somewhere).
Re: tupleof function parameters?
On Tuesday, 28 August 2018 at 06:11:35 UTC, Jon Degenhardt wrote: I'd like to create a Tuple alias representing a function's parameter list. Is there a way to do this? [...] Are you aware of https://dlang.org/phobos/std_traits.html#Parameters
tupleof function parameters?
I'd like to create a Tuple alias representing a function's parameter list. Is there a way to do this? Here's an example creating a Tuple alias for a function's parameters by hand: import std.typecons: Tuple; bool fn(string op, int v1, int v2) { switch (op) { default: return false; case "<": return v1 < v2; case ">": return v1 > v2; } } alias fnArgs = Tuple!(string, "op", int, "v1", int, "v2"); unittest { auto args = fnArgs("<", 3, 5); assert(fn(args[])); } This is quite useful. I'm wondering if there is a way to create the 'fnArgs' alias from the definition of 'fn' without needing to manually write out the '(string, "op", int, "v1", int, "v2")' sequence by hand. Something like a 'tupleof' operation on the function parameter list. Or conversely, define the tuple and use it when defining the function. The goal is to write the argument list once and use it to create both the function and the Tuple alias. That way I could create a large number of these function / arglist tuple pairs with less brittleness. --Jon
Re: Null-Coalescing Operator and Extensions
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):" IMO not to have the Elvis operator in D (actually "??" is less interesting than the Elvis "?:" because of D automatic dereference and also because of boolean eval of stuff like integers and classes instances or pointer) is not a huge issue. Not to have the safe access operator is more a problem. One is about having shorter ternary expressions (Elvis), the other is about saving sometimes 4 or 5 "&&" with at new "&&" a longer unary (Safe access).
Re: Is there a simple way to check if value is null for every case?
On Monday, 27 August 2018 at 19:36:29 UTC, aliak wrote: Then Nullable!(int*) would be the same as int*. Or even better maybe is to give a compiler error when you try and stuff a nullable type inside a Nullable. Because ... why? Isn't it arguable, whether this is desired? I mean, in the present state you can separate the cases, whether the Nullable is set or not. This is a feature. If Nullable!(int*) behaves like int*, it would be somewhat more straight forward, which is maybe also a feature. But you loose something you can do right now...
Re: Can passing an address of this to a non-copyable object be made trusted? - i.e. can I disable moving?
On Monday, 27 August 2018 at 00:15:18 UTC, Jonathan M Davis wrote: On Sunday, August 26, 2018 5:10:29 PM MDT Nicholas Wilson via So, soon™? Bah humbug. Was afraid of this :p Yeah. Hopefully, we're able to disable moving at some point in the near future. However, right now, it's definitely not possible. So, if you have a type where it won't work properly if it's ever moved, then either you need to rethink what you're doing, or you must be _very_ careful with how you use any object of that type so that you don't ever use it in a way that even might result in it being moved. - Jonathan M Davis I guess I'll just stay @system for now then. Maybe I'll be able to figure something out some time.
Re: Is there a simple way to check if value is null for every case?
On Monday, 27 August 2018 at 14:11:32 UTC, SG wrote: On Monday, 27 August 2018 at 13:02:28 UTC, rikki cattermole wrote: So Nullable in D and C# is basically the same except C#'s has language support. The big difference is that in there I could do: int? i = null; string j = null; var k = null; and test all like: i == null; j == null; k == null; but in D: Nullable!int i; auto j = null; string k = null; writefln("%s", i.isNull); // I need to invoke Nullable property isNull; writefln("%s", i == null); // I can't just do this. writefln("%s", j == null); writefln("%s", k == null); I hear you. IMO Nullable should be modified a bit to serve the purpose of turning non-nullable types in to nullable types and only that (right now it's confusing itself with an optional type). Then we could implement opEquals(typeof(null)) so that nullable == null would work. I.e. struct Nullable(T) { static if (isPointer!T) { private PointerTarget!T _value = PointerTarget!T.init; } else { private T _value = T.init; } bool opEquals(typeof(null)) { return isNull; } } Then Nullable!(int*) would be the same as int*. Or even better maybe is to give a compiler error when you try and stuff a nullable type inside a Nullable. Because ... why? Cheers, - Ali
Re: How to pass alias as template parameter?
On Monday, 27 August 2018 at 09:50:01 UTC, Andrey wrote: Hello, This code doesn't compile: --- import std.meta; import std.stdio; enum Option : string { First = "-first" , Second = "-second", Qwerty = "-qwerty" } void handler(Option option)(string[] args, ref ushort index) { writeln("Case: ", args[index]); } void handler(string arg, ref ushort index) { writeln("Default: ", arg, " at index ", index); } // Multiple issues here. for example, you call handler but it means nothing at compile time(the writeln should give that away) // You seem to think AliasSeq is a list/array when it is slightly different, nesting AliasSeq's do not produce a nested array(unfortunately, although it shouldn't be difficult to implement such a thing. alias Pair(alias key, alias value) = AliasSeq!(key, value); alias Pairs = AliasSeq!(Pair!(Option.First, handler!(Option.First)), Pair!(Option.Second, handler!(Option.Second)), handler); void parseArgs(alias sequence)(ushort index, string[] args) { alias last = sequence[$ - 1]; alias pairs = sequence[0 .. $ - 2]; for(ushort i = index; i < args.length; ++i) { string arg = args[i]; switch(arg) { static foreach(pair; pairs) { case pair.key: pair.value(args, i); break; } default: last(arg, i); break; } } } void main() { // These are run time variables, that is, the compiler does not know about them at compile time, hence you cannot use them for compile time parameters(Template parameters) ushort index = 1; string[] args = ["-second", "123", "-qaz", "true", "-first", "77", "value"]; // This makes no sense, the only sense it could make is that you mean parseArgs!(Pairs(index, args)); but index and args are runtime. If you convert them to compile time using enum then they can be passed, but Pairs is still malformed as is parseArgs. parseArgs!Pairs(index, args); } --- Output: onlineapp.d(52): Error: template instance `parseArgs!("-first", handler, "-second", handler, handler)` does not match template declaration parseArgs(alias sequence)(ushort index, string[] args) I don't understand how to pass my "Pairs" alias into template function "parseArgs". P.S. Yes, I know that exists "getopt". None of that code really makes any sense. Do you have any idea what you are actually doing? Better for you to use getopt until you learn what you are trying to do. Basically the code is so malformed in the use of meta programming that it really does not make a lot of sense. This is what you should do: 1. Write all your code without templates, don't think of meta programming! 2. Your code then will work fine with CTFE and will be optimized. e.g., suppose you have ushort index = 1; string[] args = ["-second", "123", "-qaz", "true", "-first", "77", value"]; parseArgs(index, args); Then by changing those types to enum the compiler will automatically evaluate the code at compile time for you! no meta programming involved(except the use of enum). This is actually what you need to do because using arguments is a runtime thing... if you wrote your code to take compile time arguments you can only use them at compile time, defeating the whole purpose. Your mind has not learned to divide the compile time meta programming with the runtime programming and so it looks like you are mixing the two, and they can never be mixed up! Except that runtime can be executed at compile time using a "trick"(CTFE) which can make life very easy. In fact, you always want to try to do everything as if it were runtime because you can almost always use it at compile time using CTFE. So you cover much more area than think you do. Then, naturally, you will want to make the compile time version behave a little different and you will use a little meta programming, but naturally instead of trying to force it. Then you will develop a better understanding of the meta side of programming, which is just really about making really efficient code by doing things at compile time that can be done there(such as precomputing values(which CTFE generally covers well), reducing code bloat by working in more generic type space(e.g., overloading is a form of meta programming), etc..) One of the bad things about D is that it's error messages in meta code can be total gibberish, so it is not a good idea to over complicate things. You also cannot debug the meta code nor debug string mixins and so you'll end up wasting a lot of time and not get very far. Basically you shouldn't be trying to force anything to be meta in D, It will generally natu
Re: How to pass alias as template parameter?
On Monday, 27 August 2018 at 09:50:01 UTC, Andrey wrote: alias Pair(alias key, alias value) = AliasSeq!(key, value); alias Pairs = AliasSeq!(Pair!(Option.First, handler!(Option.First)), Pair!(Option.Second, handler!(Option.Second)), handler); You can't nest AliasSeqs. If you examine Pairs with pragma(msg, ...), you'll see that the inner AliasSeqs have been expanded, and their members inserted into the outer sequence. As a result, when you attempt to iterate over the pairs later, you're actually iterating over the individual Options and handlers, one at a time: static foreach(pair; pairs) { case pair.key: pair.value(args, i); break; } Also, you can't use the dot operator to access parameters of a template like that. onlineapp.d(52): Error: template instance `parseArgs!("-first", handler, "-second", handler, handler)` does not match template declaration parseArgs(alias sequence)(ushort index, string[] args) Here again, your AliasSeq "Pairs" is being expanded into multiple template arguments, rather than being passed as a single one. If you want to pass an AliasSeq to a template, you have to use a variadic template. Further reading: https://dlang.org/spec/template.html#variadic-templates https://dlang.org/articles/ctarguments.html
Re: Is there a simple way to check if value is null for every case?
On Monday, 27 August 2018 at 14:11:32 UTC, SG wrote: On Monday, 27 August 2018 at 13:02:28 UTC, rikki cattermole wrote: So Nullable in D and C# is basically the same except C#'s has language support. Shouldn't it be in the standard library? I think it's worth it to create a feature request in Phobos for that. Or at least make a bug report. Such inconsistencies must be handled by a standard library, not manually, I believe.
the "from" template and parameterized functions
I can't get the from template [0] to work in the following situation, is it possible? --- module m; import std.stdio; package template from(string moduleName) { mixin("import from = " ~ moduleName ~ ";"); } version(works) { struct S {} void t(from!"m".S param) {} auto a = S(); } else { struct S(T) {} void t(T)(from!"m".S!T param) {} // This errors out auto a = S!int(); } void main() { t(a); } --- And the error is: onlineapp.d(15): Error: undefined identifier T onlineapp.d(21): Error: template m.t cannot deduce function from argument types !()(S!int), candidates are: onlineapp.d(15):m.t(T)(from!"m".S!T param) [0] https://forum.dlang.org/thread/hwqqfetprqhlzqpox...@forum.dlang.org
Re: Null-Coalescing Operator and Extensions
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. import std.stdio, std.typecons, std.variant, std.conv; void foo(T, U...)(T t, U u) if (is(T == Nullable!U) ) { if(t.isNull){ writeln(u); return; } writeln(t); } void foo(T, U...)(T t, U u) if (!is(T == Nullable!U) ){ if(t == null){ writeln(u); return; } writeln(t); } class C { Nullable!int m; } void main(){ Nullable!int i; auto j = null; string k = null; Variant l = null; C c = new C(); writefln("%s", i.isNull); writefln("%s", j == null); writefln("%s", k == null); writefln("%s", l == null); writefln("%s", c.m.isNull); i.foo(1); j.foo(2); k.foo(3); l.foo(4.3); c.m.foo(5); }
Re: Is there a simple way to check if value is null for every case?
On Monday, 27 August 2018 at 13:02:28 UTC, rikki cattermole wrote: So Nullable in D and C# is basically the same except C#'s has language support. The big difference is that in there I could do: int? i = null; string j = null; var k = null; and test all like: i == null; j == null; k == null; but in D: Nullable!int i; auto j = null; string k = null; writefln("%s", i.isNull); // I need to invoke Nullable property isNull; writefln("%s", i == null); // I can't just do this. writefln("%s", j == null); writefln("%s", k == null);
Re: Is there a simple way to check if value is null for every case?
On Monday, 27 August 2018 at 12:54:59 UTC, SG wrote: On Monday, 27 August 2018 at 03:21:04 UTC, rikki cattermole wrote: Templates make it the easiest way, since common patterns, like arrays, classes and pointers have the exact same null check syntax. I see. That code is only for classes. C# also has structs which are a value type. Which it would not work for. The same thing for struct in C# Struct S{ public int? i; } S.i == null; // This works nicely. You don't need isNull function for Nullable because it has a method called it. That will be preferred (hence I specifically used isNull as the name). For Variant, use hasValue. bool isNull(Variant value) { return !value.hasValue; } The problem I'm trying to solve is beyond that. This is just an example. But bear with me, right now all I want is a function to check the value from 'a' type and return if it is null. The type could be a: Class, Struct, a Basic data type, Variant, Nullable and so. And what I see, these types has different behaviors, while in C# at least for this same case, I would write the same thing in few lines to perform it, in D I found very hard. Isn't counter intuitive the way D works? Because for each type Class/Nullable you check with .isNull, for Variant with .hasValue, for string (variable is null). Thanks. hasValue isn't equivalent of isNull or is null. 'null' is valid value in Variant: import std.variant; Variant v; v = null; assert(v.hasValue);//v has value assert(v.get!(typeof(null)) is null); //value in v is null Nullable!T.isNull isn't equivalent of is null: int* i = null; Nullable!(int*) ni; ni = i; assert(ni.isNull == false); ///ni has value assert(ni is null); ///ni value is null string is null isn't equivalent of empty: string str = "test"; str = str[0 .. 0]; assert(str !is null); ///str isn't null assert(str.empty); ///str is empty
Re: Is there a simple way to check if value is null for every case?
On 28/08/2018 12:54 AM, SG wrote: The same thing for struct in C# Struct S{ public int? i; } S.i == null; // This works nicely. https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/nullable-types/index So Nullable in D and C# is basically the same except C#'s has language support.
Re: Is there a simple way to check if value is null for every case?
On Monday, 27 August 2018 at 03:21:04 UTC, rikki cattermole wrote: Templates make it the easiest way, since common patterns, like arrays, classes and pointers have the exact same null check syntax. I see. That code is only for classes. C# also has structs which are a value type. Which it would not work for. The same thing for struct in C# Struct S{ public int? i; } S.i == null; // This works nicely. You don't need isNull function for Nullable because it has a method called it. That will be preferred (hence I specifically used isNull as the name). For Variant, use hasValue. bool isNull(Variant value) { return !value.hasValue; } The problem I'm trying to solve is beyond that. This is just an example. But bear with me, right now all I want is a function to check the value from 'a' type and return if it is null. The type could be a: Class, Struct, a Basic data type, Variant, Nullable and so. And what I see, these types has different behaviors, while in C# at least for this same case, I would write the same thing in few lines to perform it, in D I found very hard. Isn't counter intuitive the way D works? Because for each type Class/Nullable you check with .isNull, for Variant with .hasValue, for string (variable is null). Thanks.
Re: How to use math functions in dcompute?
On Monday, 27 August 2018 at 09:57:18 UTC, Sobaya wrote: On Monday, 27 August 2018 at 09:41:34 UTC, 9il wrote: On Monday, 27 August 2018 at 08:25:14 UTC, Sobaya wrote: I'm using dcompute(https://github.com/libmir/dcompute). In the development, I have got to use math functions such as sqrt in @compute function. But LDC says "can only call functions from other @compute modules in @compute code", so can't I call any math functions with dcompute? Is there any way to use predefined math functions in dcompute? Thanks. You may want to try ldc.intrinsics / mir.math.common Do you mean llvm_sqrt in ldc.intrinsics? These functions are also not @compute code, so they cause the same error. Thanks for bringing this to my attention, will fix soon. In the meantime you may declare your own intrinsics in a @compute module and it should work. as in @compute module mymath; pragma(LDC_intrinsic, "llvm.sqrt.f#") T llvm_sqrt(T)(T val) if (__traits(isFloating, T)); This will work if you are targeting CUDA, SPIRV may not like it because the backend is less... mature.
Re: How to mixin repeated text?
On Monday, 27 August 2018 at 11:56:08 UTC, Kamil Koczurek wrote: Mixins seem to be an overkill here. Maybe something like this would suffice: data[index + 1 .. index + 5].map!(k => k[0]).array == "" Here there is dynamic code, with memory allocs. I found solution: --- import std.meta; import std.traits; import std.stdio; import std.array : join; import std.algorithm.iteration : map; import std.conv : to; import std.range; string qaz(alias args, alias index, ubyte count)() { return iota(1, count).map!(j => args.stringof ~ '[' ~ index.stringof ~ '+' ~ j.to!string ~ "][0] == '&'").join("||"); } void main() { ushort index = 1; string[] args = ["&second", "123", "&qaz", "true", "&first", "77", "&value"]; if(index + 1 >= args.length || mixin(qaz!(args, index, 4))) { writeln(qaz!(args, index, 4)()); } } ---
Re: How to mixin repeated text?
On Monday, 27 August 2018 at 11:52:02 UTC, Andrey wrote: Hello again, I have this part of code: ... if(index + 3 >= data.length || data[index + 1][0] == '&' || data[index + 2][0] == '&' || data[index + 3][0] == '&' || data[index + 4][0] == '&') { writeln("Some text..."); } I don't want to write manually these four "or" conditions because in each case I know at compile time how many conditions should be. I would be great if I could do something like this: if(index + 3 >= data.length || mixin OrCondition!4) { ... } where "OrCondition" will insert text using this expression: data[index + j][0] == '&' // j is between [1 and 4] I know that it is possible but don't know how to implement... Mixins seem to be an overkill here. Maybe something like this would suffice: data[index + 1 .. index + 5].map!(k => k[0]).array == ""
How to mixin repeated text?
Hello again, I have this part of code: ... if(index + 3 >= data.length || data[index + 1][0] == '&' || data[index + 2][0] == '&' || data[index + 3][0] == '&' || data[index + 4][0] == '&') { writeln("Some text..."); } I don't want to write manually these four "or" conditions because in each case I know at compile time how many conditions should be. I would be great if I could do something like this: if(index + 3 >= data.length || mixin OrCondition!4) { ... } where "OrCondition" will insert text using this expression: data[index + j][0] == '&' // j is between [1 and 4] I know that it is possible but don't know how to implement...
Re: How to use math functions in dcompute?
On Monday, 27 August 2018 at 09:57:18 UTC, Sobaya wrote: On Monday, 27 August 2018 at 09:41:34 UTC, 9il wrote: On Monday, 27 August 2018 at 08:25:14 UTC, Sobaya wrote: I'm using dcompute(https://github.com/libmir/dcompute). In the development, I have got to use math functions such as sqrt in @compute function. But LDC says "can only call functions from other @compute modules in @compute code", so can't I call any math functions with dcompute? Is there any way to use predefined math functions in dcompute? Thanks. You may want to try ldc.intrinsics / mir.math.common Do you mean llvm_sqrt in ldc.intrinsics? These functions are also not @compute code, so they cause the same error. Ah, interesting
Re: How to use math functions in dcompute?
On Monday, 27 August 2018 at 09:41:34 UTC, 9il wrote: On Monday, 27 August 2018 at 08:25:14 UTC, Sobaya wrote: I'm using dcompute(https://github.com/libmir/dcompute). In the development, I have got to use math functions such as sqrt in @compute function. But LDC says "can only call functions from other @compute modules in @compute code", so can't I call any math functions with dcompute? Is there any way to use predefined math functions in dcompute? Thanks. You may want to try ldc.intrinsics / mir.math.common Do you mean llvm_sqrt in ldc.intrinsics? These functions are also not @compute code, so they cause the same error.
How to pass alias as template parameter?
Hello, This code doesn't compile: --- import std.meta; import std.stdio; enum Option : string { First = "-first" , Second = "-second", Qwerty = "-qwerty" } void handler(Option option)(string[] args, ref ushort index) { writeln("Case: ", args[index]); } void handler(string arg, ref ushort index) { writeln("Default: ", arg, " at index ", index); } alias Pair(alias key, alias value) = AliasSeq!(key, value); alias Pairs = AliasSeq!(Pair!(Option.First, handler!(Option.First)), Pair!(Option.Second, handler!(Option.Second)), handler); void parseArgs(alias sequence)(ushort index, string[] args) { alias last = sequence[$ - 1]; alias pairs = sequence[0 .. $ - 2]; for(ushort i = index; i < args.length; ++i) { string arg = args[i]; switch(arg) { static foreach(pair; pairs) { case pair.key: pair.value(args, i); break; } default: last(arg, i); break; } } } void main() { ushort index = 1; string[] args = ["-second", "123", "-qaz", "true", "-first", "77", "value"]; parseArgs!Pairs(index, args); } --- Output: onlineapp.d(52): Error: template instance `parseArgs!("-first", handler, "-second", handler, handler)` does not match template declaration parseArgs(alias sequence)(ushort index, string[] args) I don't understand how to pass my "Pairs" alias into template function "parseArgs". P.S. Yes, I know that exists "getopt".
Re: How to use math functions in dcompute?
On Monday, 27 August 2018 at 08:25:14 UTC, Sobaya wrote: I'm using dcompute(https://github.com/libmir/dcompute). In the development, I have got to use math functions such as sqrt in @compute function. But LDC says "can only call functions from other @compute modules in @compute code", so can't I call any math functions with dcompute? Is there any way to use predefined math functions in dcompute? Thanks. You may want to try ldc.intrinsics / mir.math.common
How to use math functions in dcompute?
I'm using dcompute(https://github.com/libmir/dcompute). In the development, I have got to use math functions such as sqrt in @compute function. But LDC says "can only call functions from other @compute modules in @compute code", so can't I call any math functions with dcompute? Is there any way to use predefined math functions in dcompute? Thanks.
Re: Null-Coalescing Operator and Extensions
On Saturday, 25 August 2018 at 19:16:26 UTC, Jacob Carlborg wrote: On 2018-08-25 15:33, SG wrote: Hi, 1) I program in C# and I'm wondering if there is something like ?? (Null-Coalescing Operator) in D? (I remember some proposals in the past). Not in the language but it can be implemented as a library function by overloading "opDispatch". See [1] for an example. [1] https://github.com/jacob-carlborg/dlp/blob/9d524e282803070022848c01cf6cd25a61025004/source/dlp/core/optional.d#L228-L238 In the same vain there's "safeAccess" in my user library, see https://github.com/BBasile/iz/blob/master/import/iz/sugar.d#L1658. It's more or less the same specific D pattern (opDispatch), although the OP asked for "??" and not for "?.", which is strange. I find that the later misses more as a builtin operator.
Re: Null-Coalescing Operator and Extensions
On Saturday, 25 August 2018 at 19:16:26 UTC, Jacob Carlborg wrote: On 2018-08-25 15:33, SG wrote: Hi, 1) I program in C# and I'm wondering if there is something like ?? (Null-Coalescing Operator) in D? (I remember some proposals in the past). Not in the language but it can be implemented as a library function by overloading "opDispatch". See [1] for an example. [1] https://github.com/jacob-carlborg/dlp/blob/9d524e282803070022848c01cf6cd25a61025004/source/dlp/core/optional.d#L228-L238 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): struct NullCoalesce { static auto opBinaryRight(string op : "|", T)(T lhs) { return NullCoalesceImpl!T(lhs); } } alias NullCoalesce _; struct NullCoalesceImpl(T) { T value; auto opBinary(string op = "|", R)(lazy R rhs) { if (value is null) return rhs; return value; } } unittest { int* a = null; int b = 3; assert(*(a |_| &b) == 3); } -- Simen