Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More null-aware operators #27716

Open
mehmetf opened this issue Nov 1, 2016 · 8 comments
Open

More null-aware operators #27716

mehmetf opened this issue Nov 1, 2016 · 8 comments
Labels
area-language Dart language related items (some items might be better tracked at github.com/dart-lang/language). core-m type-enhancement A request for a change that isn't a bug

Comments

@mehmetf
Copy link
Contributor

mehmetf commented Nov 1, 2016

It would be nice to have a shorthand for this:

val == null ? null : method(val);

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:

double convertFromMicro(Int64 value) =>
    value == null ? null : value.toDouble() / _microDollars;

value?.toDouble() / _microDollars would blow up if value is null.

@floitschG floitschG added the area-language Dart language related items (some items might be better tracked at github.com/dart-lang/language). label Nov 2, 2016
@lrhn lrhn added the type-enhancement A request for a change that isn't a bug label Nov 2, 2016
@lrhn
Copy link
Member

lrhn commented Nov 2, 2016

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!" :)

@floitschG
Copy link
Contributor

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.

@lrhn
Copy link
Member

lrhn commented Nov 2, 2016

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
  • etc.

Still, if we can make it work, it would be great.

@mehmetf
Copy link
Contributor Author

mehmetf commented Nov 2, 2016

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 :-).

@lrhn lrhn added the core-m label Dec 6, 2018
@jamesderlin
Copy link
Contributor

Also see dart-lang/language#360.

@jamesderlin
Copy link
Contributor

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/.

@lrhn
Copy link
Member

lrhn commented Apr 19, 2021

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.

@lrhn
Copy link
Member

lrhn commented Apr 19, 2021

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).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-language Dart language related items (some items might be better tracked at github.com/dart-lang/language). core-m type-enhancement A request for a change that isn't a bug
Projects
None yet
Development

No branches or pull requests

4 participants