Language: Null-aware elements

Created on 23 Apr 2019  路  8Comments  路  Source: dart-lang/language

I would love to have a "null-aware" operator for adding an element to a list if it is non-null.

[
  foo,
  ?bar,
]

This would be equivalent to:

[
  foo,
  if (bar != null) bar,
]

I've been trying out the new "UI-as-code" features in the angular codebase, and find that I can't convert a common pattern to use the new element syntax.

We often iterate over a list, adding elements to a new list when the value is non-null.

var result = [];
for (var node in nodes) {
  var value = convert(node);
  if (value != null) result.add(value);
}

It would be pretty nice if I could instead use the new syntax:

var result = [
  for (var node in nodes) ?convert(node);
]
feature small-feature

Most helpful comment

We could introduce a let construct.

[ let tmp = something in if (tmp != null) tmp ]

which is obviously not as short as [? something], but it is more generally useful.
The current existing workaround is

[ for (var tmp in [something]) if (tmp != null) tmp ]

or

[... [something].where(isNotNull)]

or (after NNBD)

[... [something].whereType<Object>()]

All of these will likely introduce an intermediate list, with only the first example being likely to have that optimized away.

All 8 comments

In the short term, you can nest the if inside the for:

var result = [
  for (var node in nodes) if (node != null) convert(node)
]

@bwilkerson I want to check the value of convert(node), not node for nullability. You're example would require me to call convert twice, which I do not want to do:

var result = [
  for (var node in nodes) if (convert(node) != null) convert(node)
]

cc @munificent

This is an interesting corner. We could do some kind of single-value null-aware element syntax like you suggest. I'm very hesitant to pile more semantics onto ? because it's already quite overloaded in the grammar (postfix for nullable types, in null-aware operators, and in conditional expressions).

In many cases, you can use the other UI-as-code features like Brian suggests, but in this case you want to avoid any redundant computation. Of course, the natural way to do that is with a local variable, which makes me think building the list imperatively like you do today probably is the best approach.

We could introduce a let construct.

[ let tmp = something in if (tmp != null) tmp ]

which is obviously not as short as [? something], but it is more generally useful.
The current existing workaround is

[ for (var tmp in [something]) if (tmp != null) tmp ]

or

[... [something].where(isNotNull)]

or (after NNBD)

[... [something].whereType<Object>()]

All of these will likely introduce an intermediate list, with only the first example being likely to have that optimized away.

See also #219. Is there any difference?

I think the only difference is that in #219, you propose allowing ? to elide arguments in argument lists as well. Otherwise, I think they're the same.

I was just trying to find more use cases for an operator, and the discussion mentioned even more potential uses, but this has to be filtered, for sure. Maybe there's a way to merge these 2 discussions?

Was this page helpful?
0 / 5 - 0 ratings