dart-lang / language

Design of the Dart language
Other
2.67k stars 205 forks source link

Support nullableCallable?() for nullable/optional callbacks consistently to nullableCallable!() #2142

Open RastislavMirek opened 2 years ago

RastislavMirek commented 2 years ago

Currently, Dart only supports "force unwrap" calling of optional callables e.g.:

final VoidCallback? nullableCallback = (){};
...
nullableCallback!();

Replacing the exclamation mark by a question mark in the snippet above (producing nullableCallback?();) results in a compile-time error. Therefore, if we want the callback to execute only if it is not null, the code needs to read:

final VoidCallback? nullableCallback = condition ? (){} : null; // `condition` may or may not be true
...
if (nullableCallback != null) {
  nullableCallback!();
}

I suggest supporting the ? syntax in place of ! with semantics "Only call the function/callable if it is not null", which would allow removing the if command and simplify the above code into:

final VoidCallback? nullableCallback = condition ? (){} : null; // condition may or may not be true
...
nullableCallback?();

In addition to being practical and more concise, this would make the force unwrap and optional chaining syntax more consistent throughout the language because calling a function/callable is currently the only place where question mark cannot be used in place of exclamation mark.

Also, this is a standard feature of most other null-safe languages.

rrousselGit commented 2 years ago

You can do:

nullableCallback?.call();
RastislavMirek commented 2 years ago

You can do:

nullableCallback?.call();

All right, but why not directly nullableCallback?();? It is more consistent, shorter, more readable...

I do not see why I can shorten nullableCallback!.call(); into nullableCallback!(); but cannot do the same with nullableCallback?.call();. It is inconsistent and unexpected, especially for Dart beginners (I teach Dart/Flutter at a university, so I can see many things through their eyes).

lrhn commented 2 years ago

There are syntax ambiguity issues (as usual), like { a ? ( b ) : c }. We generally always read that as a conditional expression, and can keep doing that. It's not different from {a ? [ b ] : c}, so not a new problem.

RastislavMirek commented 2 years ago

I know very little about Dart compiler but generally speaking, there are 2 ways how to resolve syntax ambiguity pointed to by @lrhn:

  1. The good way: If the ? has a corresponding colon within the same command, it is a ternary operator, not an optional function call. This may be harder to implement but it is the best way to go.
  2. Some languages require the ternary ? to be separated from the condition by empty space while also requiring that the chaining ? follows directly after function/callable. This is an easy solution. However, it would not be constant with how Dart treats spacing and it would be a breaking change for the ternary operator. The breaking change alone is not worth the benefits IMO.