Open mehmetf opened 7 years ago
It is a pattern that occurs reasonably often. It's worth considering.
It's a "null guard" rather than a "null replacement", similar to the use of the JavaScript &&
operator in x && x.foo()
(which is what x?.foo()
does in Dart) and x && foo(x)
(which is the case that Dart doesn't have a shorthand for).
"All the good operators are taken!" :)
Fwiw, we are considering shortcutting all following member calls, when the first ?.
fails.
That is o?.foo.bar
would be correct (and not require a ?.
for the second .
anymore). In that case we should just continue doing this for operators too, and your example could be simplified:
double convertFromMicro(Int64 value) => value?.toDouble() / _microDollars;
It wouldn't work for the direct operator case, though: value / 499
.
I personally don't think that extending the reach of the ?.
operation to surrounding operators is viable.
It's possible, defining it so that any member called on the result is also ignored (which ends at the point where you use the value itself for assignment or as a function parameter), but I think it will be too confusing. I can't decide, of the top of my head, what all of the following would mean:
1 + x?.foo
x?.foo + 1
++x?.foo
-x?.foo
x?.foo == 42
Still, if we can make it work, it would be great.
I would also vote against handling this via extending the reach of ?. operator. I believe it would create readability issues and might lead to more problems than it solves. I like the current explicit way of null guarding.
For instance, people might get comfortable and start writing formulas like ((val?.toDouble() / 42) * 170).toFloor()
. It isn't clear to me at all how far ?. reaches. I would rather have an explicit piece of code that says when val is null, return null.
My original thought was to use the bang op in conjunction with ?? which universally means 'not'. Basically, if LHS null then DO NOT eval the RHS.
val !?? ((val.toDouble() / 42) * 170).toFloor()
We are getting dangerously close to emojis :-).
My original thought was to use the bang op in conjunction with ?? which universally means 'not'. Basically, if LHS null then DO NOT eval the RHS.
val !?? ((val.toDouble() / 42) * 170).toFloor()
We are getting dangerously close to emojis :-).
Or ??!
, and Dart could pretend to have C trigraphs. ;)
Anyway, this probably doesn't need more data points for motivation, but an inverted ??
operator would address https://stackoverflow.com/questions/67136658/.
An "xargs"/"applyTo" like extension function can work, but it means introducing a closure, which is heavyweight in both syntax and execution overhead.
It does solve the issue of delimiting the code affected by the check, something most proposals fail to do, and which I think is essential to making the feature practically useful. The ?.
works because users understand how far it reaches (they're probably slightly wrong, but equally likely they'll never notice).
It works today, which is awesome compared to all other suggestions so far. 👍
Naming. Is. Hard. (So is punctuation, but at least this avoids using new operators).
Maybe call it to
: y?.to(print)
. It's such a generic operation, and one that shouldn't be too verbose, so the name should be short and general.
Most likely we can get inlining most of the time. We're calling a static function (extension methods are static functions) so that's ripe for inlining, and then it should be fairly simple to see that the function literal can be inlined too. It's just not something that can be promised in general since the language doesn't require it. Some compilers might optimize for size over speed, and inlining can cause code duplication (it won't here, but the compiler probably needs to try before it can see whether it blows up or not).
It would be nice to have a shorthand for this:
This is the opposite of
val ?? method(val)
which only returns method(val) when val is null.We love the null friendly operators so it bugs me a lot that I can't do this. Normally you would not need it if method can do ?. everywhere but sometimes the shorthand helps. For instance, some operators are not null friendly:
value?.toDouble() / _microDollars
would blow up if value is null.