www.digitalmars.com         C & C++   DMDScript  

digitalmars.dip.ideas - Elvis operator - shortened ternary operator

reply Andrey Zherikov <andrey.zherikov gmail.com> writes:
See [wiki](https://en.wikipedia.org/wiki/Elvis_operator) for 
details.

Proposed syntax:
```d
A ?: B
```
This is equivalent to:
```d
auto R = A;  // temporary (hidden) variable
(cast(bool) R) ? R : B;
```

Semantics: return `A` if it's truthy, or `B` otherwise.

Benefit: avoids evaluating if `A` twice which might be a call to 
some function with side effects.
Mar 26 2025
next sibling parent reply Dukc <ajieskola gmail.com> writes:
On Thursday, 27 March 2025 at 00:26:27 UTC, Andrey Zherikov wrote:
 See [wiki](https://en.wikipedia.org/wiki/Elvis_operator) for 
 details.

 Proposed syntax:
 ```d
 A ?: B
 ```
 This is equivalent to:
 ```d
 auto R = A;  // temporary (hidden) variable
 (cast(bool) R) ? R : B;
 ```

 Semantics: return `A` if it's truthy, or `B` otherwise.

 Benefit: avoids evaluating if `A` twice which might be a call 
 to some function with side effects.
I believe we already have this! ```d A || B; ```
Mar 28 2025
parent reply matheus. <matheus gmail.com> writes:
On Friday, 28 March 2025 at 09:57:55 UTC, Dukc wrote:
 On Thursday, 27 March 2025 at 00:26:27 UTC, Andrey Zherikov 
 wrote:
 See [wiki](https://en.wikipedia.org/wiki/Elvis_operator) for
 I believe we already have this!

 ```d
 A || B;
 ```
I don't think this is what Andrey want, example: import std.stdio; void main(){ int a = 13; int b = 2; auto c = a||b; writeln(c); auto d = a ? a : b; writeln(d); } output: true 13 I think he wants the latter as his link too this matter explain: https://en.wikipedia.org/wiki/Elvis_operator . Matheus.
Mar 28 2025
next sibling parent Dukc <ajieskola gmail.com> writes:
On Friday, 28 March 2025 at 12:22:24 UTC, matheus. wrote:
 void main(){
     int a = 13;
     int b = 2;
     auto c = a||b;
     writeln(c);
     auto d = a ? a : b;
     writeln(d);
 }

 output:
 true
 13
Oh, I somehow thought that both would return 13. Such a slight but annoying difference!
Mar 28 2025
prev sibling parent Andrey Zherikov <andrey.zherikov gmail.com> writes:
On Friday, 28 March 2025 at 12:22:24 UTC, matheus. wrote:
 On Friday, 28 March 2025 at 09:57:55 UTC, Dukc wrote:
 On Thursday, 27 March 2025 at 00:26:27 UTC, Andrey Zherikov 
 wrote:
 See [wiki](https://en.wikipedia.org/wiki/Elvis_operator) for
 I believe we already have this!

 ```d
 A || B;
 ```
I don't think this is what Andrey want, example: import std.stdio; void main(){ int a = 13; int b = 2; auto c = a||b; writeln(c); auto d = a ? a : b; writeln(d); } output: true 13 I think he wants the latter as his link too this matter explain: https://en.wikipedia.org/wiki/Elvis_operator . Matheus.
Yes. The main benefit is that `a` is not calculated twice if it's a function like here: `auto d = a() ? a() : b();`
Mar 28 2025
prev sibling next sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Thursday, 27 March 2025 at 00:26:27 UTC, Andrey Zherikov wrote:
 See [wiki](https://en.wikipedia.org/wiki/Elvis_operator) for 
 details.

 Proposed syntax:
 ```d
 A ?: B
 ```
 This is equivalent to:
 ```d
 auto R = A;  // temporary (hidden) variable
 (cast(bool) R) ? R : B;
 ```

 Semantics: return `A` if it's truthy, or `B` otherwise.

 Benefit: avoids evaluating if `A` twice which might be a call 
 to some function with side effects.
Library version: ```d auto orElse(T)(T a, lazy T b) { return a ? a : b; } unittest { string s1 = "hello"; string s2 = null; assert(s1.orElse("goodbye") == "hello"); assert(s2.orElse("goodbye") == "goodbye"); } ```
Mar 28 2025
next sibling parent reply matheus <matheus gmail.com> writes:
On Friday, 28 March 2025 at 17:06:56 UTC, Paul Backus wrote:
 ...
 Library version:
 ...
This is a cool alternative, and I think that I saw this before, maybe (https://code.dlang.org/packages/expected/0.2.3). Now I wonder... you know what would be the thing? - If we could define our own OP, imagine same thing but instead of: A.or(B); <- Shorted version of orElse. A :? B; <- we could define a new unused "op" acting like <,>,&&,||... The difference may look minimal, but the latter really looks nicer, and it's something barely seem in others language. Maybe parsing could be a pain, but anyway just ventilating... Matheus.
Mar 28 2025
parent reply Paul Backus <snarwin gmail.com> writes:
On Friday, 28 March 2025 at 19:16:12 UTC, matheus wrote:
 Now I wonder... you know what would be the thing? - If we could 
 define our own OP, imagine same thing but instead of:

 A.or(B); <- Shorted version of orElse.

 A :? B;  <- we could define a new unused "op" acting like 
 <,>,&&,||...

 The difference may look minimal, but the latter really looks 
 nicer, and it's something barely seem in others language.
Personally I would much, much rather have custom "operators" written using letters and words, which I can easily read and search for, than with symbols and punctuation marks.
Mar 28 2025
parent reply Dejan Lekic <dejan.lekic gmail.com> writes:
On Friday, 28 March 2025 at 19:47:11 UTC, Paul Backus wrote:
 Personally I would much, much rather have custom "operators" 
 written using letters and words, which I can easily read and 
 search for, than with symbols and punctuation marks.
100% I dream of having something like this: https://kotlinlang.org/docs/functions.html#infix-notation I wonder would that be too much for D, it already has too many features...
Apr 01 2025
parent Quirin Schroll <qs.il.paperinik gmail.com> writes:
On Tuesday, 1 April 2025 at 08:49:17 UTC, Dejan Lekic wrote:
 On Friday, 28 March 2025 at 19:47:11 UTC, Paul Backus wrote:
 Personally I would much, much rather have custom "operators" 
 written using letters and words, which I can easily read and 
 search for, than with symbols and punctuation marks.
100% I dream of having something like this: https://kotlinlang.org/docs/functions.html#infix-notation I wonder would that be too much for D, it already has too many features...
That particular thing should be an operator. The general function-as-an-infix operator thing possibly complicates the parser a lot. It’s a completely different idea that definitely requires a DIP.
Apr 14 2025
prev sibling parent Quirin Schroll <qs.il.paperinik gmail.com> writes:
On Friday, 28 March 2025 at 17:06:56 UTC, Paul Backus wrote:
 On Thursday, 27 March 2025 at 00:26:27 UTC, Andrey Zherikov 
 wrote:
 See [wiki](https://en.wikipedia.org/wiki/Elvis_operator) for 
 details.

 Proposed syntax:
 ```d
 A ?: B
 ```
 This is equivalent to:
 ```d
 auto R = A;  // temporary (hidden) variable
 (cast(bool) R) ? R : B;
 ```

 Semantics: return `A` if it's truthy, or `B` otherwise.

 Benefit: avoids evaluating if `A` twice which might be a call 
 to some function with side effects.
Library version: ```d auto orElse(T)(T a, lazy T b) { return a ? a : b; } unittest { string s1 = "hello"; string s2 = null; assert(s1.orElse("goodbye") == "hello"); assert(s2.orElse("goodbye") == "goodbye"); } ```
That `orElse` cannot preserve value categories. Adding `auto ref` to ´lazy T b` isn’t something the language supports. I’m not sure why, maybe it’s merely an oversight, maybe it’s because it’s complicated. ```d auto ref orElse(T, DG)(auto ref T a, DG b) { return a ? a : b(); } void test() { int x; int y; x.orElse(auto ref () => y) = 10; assert(y == 10); x = 1; x.orElse(auto ref () => y) = 11; assert(x == 11 && y == 10); } ``` It works, but it’s not really great.
Apr 14 2025
prev sibling parent Quirin Schroll <qs.il.paperinik gmail.com> writes:
On Thursday, 27 March 2025 at 00:26:27 UTC, Andrey Zherikov wrote:
 See [wiki](https://en.wikipedia.org/wiki/Elvis_operator) for 
 details.

 Proposed syntax:
 ```d
 A ?: B
 ```
 This is equivalent to:
 ```d
 auto R = A;  // temporary (hidden) variable
 (cast(bool) R) ? R : B;
 ```

 Semantics: return `A` if it's truthy, or `B` otherwise.

 Benefit: avoids evaluating if `A` twice which might be a call 
 to some function with side effects.
The lowering is actually tricky because the right-hand side ought to be evaluated only if the left-hand side is `false` as a condition. Proposing a lowering of an expression to a statement is making things difficult. The best lowering I could come up with is: ```d lhs ?: rhs // to (auto ref (auto ref __lhs) => __lhs ? __lhs : rhs)(lhs) ``` The right-hand side can be placed in the lambda as-is because it only occurs once and in fact has to be put there because passing it as a parameter evaluates it prematurely. The left-hand side *must* be evaluated first. The `auto ref` is needed to enable `(l ?: r) = x`. It would be surprising if that didn’t work if both `l` and `r` are rvalues since `(l ? l : r) = x` does work. Lastly, the `cast(bool)` is incorrect: An explicit cast to bool triggers `opCast` if present, which is something you don’t want in general, e.g. when you have a class with `opCast` and an object `c`, then `if (c)` performs a nullity check, whereas `if (cast(bool) c)` lowers to `if (c.opCast!bool)` and that does whatever it does, but certainly doesn’t check for null, but assumes it’s not null. Bottom line is, such a trivial lowering is an enhancement issue, but needs no DIP. There are virtually no surprises to be expected, no weird issues, and that is obvious; it’s just a matter of opinion if the addition provides enough value to the language and maybe its syntax (because `??` is a contender). That discussion is simply too minor to warrant a DIP. Given how many languages with similar syntax have it, it’s likely the assessment is that it does provide enough value.
Apr 14 2025