dart-lang / dart-lang/language
Function literal syntax improvements akin to Kotlin
- Dominant language
- TeX
- Stars
- 2.9k
- Forks
- 239
- Avg merge
- 2d 18h
- Merged PRs (30d)
- 14
Description
Function literals are one of the most used language constructs in Dart, at least in my experience of using Flutter. I propose to change the syntax of function literals mainly to improve readability, but also to reduce verbosity and (perhaps) inconsistency. These changes come in a couple of ways, that I will detail.
### Passing a function literal to the last parameter
[For more discussion regarding this topic see #344]
Say there is a function named `if2` that takes 3 boolean values and runs the function passed as the 4th parameter if exactly 2 of the 3 values are true.
At the moment, using that function would look like this:
```dart
if2(x > 4, x % 2 == 0, x < 10, (){
print(x);
print(x + 2);
});
```
This code would become more readable if a function literal that is passed as the corresponding argument can be placed outside the parentheses like so:
```dart
if2(x > 4, x % 2 == 0, x < 10) {
print(x);
print(x + 2);
};
```
Note that this is very similar to a normal if statement:
```dart
if(x > 4) {
print(x);
print(x + 2);
}
```
~~If `if2` accepted a function with 3 integer arguments we can perhaps write it like this:~~
```dart
if2(x > 4, x % 2 == 0, x < 10)(a,b,c) {
print(x);
print(x + 2);
print(a+b+c);
};
```
This is actually incompatible with the next syntax change. This code:
```dart
if2(x, y, z) {
print(x);
print(x + 2);
};
```
Would be ambiguous between "A function that accepts 3 arguments and a function literal" and "A function that accepts a function literal that accepts 3 arguments".
One option then is to move the function literal arguments inside the curly brackets like this:
```dart
if2(x,y,z){(a,b,c)=>
//
};
```
And then perhaps make brackets around the parameters optional:
```dart
if2(x, y, z){a,b,c=>
//
};
```
A downside of this is that it's very different from the current dart syntax.
Or perhaps add a mandatory comma between the function literal and the other parameters:
```dart
// If2 accepts 3 normal arguments and a function literal
if2(x,y,z), {
//
};
```
```dart
// If2 accepts a function literal with 3 arguments
if2(x ,y ,z){
//
};
```
One problem I see with this is that you can't read it from left to right - you don't know what you are reading until you encounter that `,`.
### Function as the only parameter`
If a function accepts a function as its only parameter, for example:
`void exampleFunc(void Function()){/*...*/}`
there is no need to have brackets at all:
```dart
exampleFunc {
print("hello");
print("world");
};
```
Take this real world example:
```dart
AuthenticationController(){
FirebaseAuth.instance.currentUser().then((fbUser) {
setState(() {
statusUndetermined = false;
if (fbUser != null) {
_user = User(fbUser?.displayName);
}
});
});
}
```
This code appears extremely nested because of all the function literals. However with these improvements it looks like so:
```dart
AuthenticationController(){
FirebaseAuth.instance.currentUser().then {fbUser->
setState {
statusUndetermined = false;
if (fbUser != null) {
_user = User(fbUser?.displayName);
}
};
};
}
```
Which is a lot cleaner.
`setState` is one of the most used functions of Flutter, and would benefit from this immensely.
### it: implicit name of a single parameter
eernstg already did a good job of explaining it: #265
### Implicit return of the last statement
With the changes listed thus far, using something like `map` is still more verbose than it could be.
You either have to use the old syntax:
```dart
var list = [1,2,3];
var mapped = list.map((x) => x+2);
```
Or the new syntax:
```dart
var mapped = list.map {return it +2;}
```
Which is why I propose to remove the need to type `return` at all:
```dart
var mapped = list.map {it +2;};
```
There is 2 ways to go about this. Either make it happen only where is one statement, in which case it would look like this:
```dart
// One statement
var mapped = list.map {it +2};
```
```dart
// More than one statement
var mapped = list.map {
var calculation= calculation(it);
return it +2 + calculation(calculation);
};
```
Or make it so the last statement is always returned:
```dart
// One statement
var mapped = list.map {it +2;};
```
```dart
// More than one statement
var mapped = list.map {
var calculation= calculation(it);
it +2 + calculation(calculation);
};
```
**Important note:** this is by no means a final draft of the feature. I made this issue merely to start conversation about the topic, as it's one of my main gripes with the language as opposed to Kotlin.
Contributor guide
Research direction
Start by reviewing the proposed syntax changes and the linked discussions in #344 and #265. Compare the alternatives and their ambiguities against Dart's existing function-literal syntax. Done would require a decided, sufficiently specified language change rather than an implementation patch.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- dart
- Domain
- compilers
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 15/100