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

Null safety: null-aware operator for constructor or function call arguments #1039

Open
spkersten opened this issue Jun 18, 2020 · 10 comments
Open
Labels
feature Proposed language feature that solves one or more problems null-aware-expressions Issues proposing new expressions to manage null

Comments

@spkersten
Copy link

We have this pattern a lot in our code:

SomeWidget(
  optionalParameter1: foo == null ? null : OtherWidget(requiredParameter: foo, otherParameter: 42),
  optionalParameter2: bar == null ? null : someFunction(/* requiredParameter */bar, otherData),
)

It would help readability if there were a similar null-aware operator like for a?[1] and foo?.bar. Or another way to avoid foo == null ? null : ....

@spkersten spkersten added the feature Proposed language feature that solves one or more problems label Jun 18, 2020
@leafpetersen
Copy link
Member

cc @lrhn @munificent @eernstg I know we discussed this, do we have an issue for it anywhere? I have also seen this pattern come up a fair bit in migrated code.

@mateusfccp
Copy link
Contributor

mateusfccp commented Jun 18, 2020

It would be nice if we could use a wildcard-like parameter, like:

SomeWidget(
    optionalParameter1: foo ??. OtherWidget(requiredParameter: _, otherParameter: 42),
    optionalParameter2: bar ??. someFunction(_, otherData),
)

@rrousselGit
Copy link

There are multiple issues requesting "if expressions" (like #820), which relates to this problem among other things:

SomeWidget(
  optionalParameter1: if (foo! = null) OtherWidget(requiredParameter: foo, otherParameter: 42),
  optionalParameter2: if (bar ! = null) someFunction(/* requiredParameter */bar, otherData),
) 

@fsteenkamp
Copy link

@spkersten as somebody whose busy working in a codebase where we had to do that a lot...I can tell you, the better solution is to clean your data up, I've spent the last four months typing up our Node API to get around this issue...and I don't regret it one bit :)

@spkersten
Copy link
Author

@Ferdzzzzzzzz What do you mean by "clean up"? Some data is optional.

@fsteenkamp
Copy link

fsteenkamp commented Jun 19, 2020

@spkersten optional data often means that the data isn't very well thought out, the goal is usually to make illegal states unrepresentable, it sounds strange but when you really dive deep into the data you can usually find a way to remove nulls from the equation :)

@spkersten
Copy link
Author

@Ferdzzzzzzzz The example in that article is about several optional fields in a data type which have some implicit conditions about which might be none. I agree that using sum types is better in that case (if Dart would support it in a convenient way). However, there are valid cases where a field is optional.

@lrhn
Copy link
Member

lrhn commented Jun 19, 2020

There are several different issues requesting a solution to different aspects of the same problem:

It all boils down to wanting to only evaluate some expression if a particular part of it is non-null.

The simplest approach is the one proposed here, where all you get is a guarded promoting short-circuit check so you can gate on the nullability of a single variable:

int? foo = ...;
var z = foo ?!  (foo + 2); // equivalent to `foo == null ? null : (foo + 2)`.

This would promote foo to non-nullable in the second operand of ?!, and not evaluate it at all if foo is null.

It won't help you as much with non-promotable variables or non-variable expressions.

@kkazuo
Copy link

kkazuo commented Aug 10, 2020

GCC has the conditional expression.
(https://gcc.gnu.org/onlinedocs/gcc/Conditionals.html#Conditionals)

in GCC

foo ?: bar; // equivalent to `foo ? foo : bar`. `foo` evaluates once not twice.

If I could go back before that Dart get ?? operator,

int? foo = ...;
var x = foo ?? (foo + 2); // equivalent to `foo != null ? (foo + 2) : null`.
var z = foo ?: bar;       // equivalent to `foo != null ? foo : bar`. currently `??` in Dart.

because I came from mainly C background.

@eernstg
Copy link
Member

eernstg commented Aug 10, 2020

Note that there's some overlap between these "non-null aware" expressions and some existing null-aware operations:

extension on int {
  int plus(int other) => this + other;
}

void main() {
  int? foo = ...;
  var x = foo?.plus(2); // Same as `foo ?! (foo + 2)`.
}

For syntactic reasons ?. won't work for operator invocations. We could perhaps add support for ?+ etc. such that it could be written as foo ?+ 2, but even that won't cover other cases like foo ?! print("Result: $foo plus 2 is ${foo + 2}").

We could use anonymous methods to express the same thing (still avoiding evaluation of the receiver expression foo multiple times):

void main() {
  int? foo = ...;
  var x = foo?.=> this + 2;
  foo?.{ print("Result: $this plus 2 is ${this + 2}"); };
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature Proposed language feature that solves one or more problems null-aware-expressions Issues proposing new expressions to manage null
Projects
None yet
Development

No branches or pull requests

8 participants