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

Function literal syntax improvements akin to Kotlin #342

Open
natanfudge opened this issue May 5, 2019 · 0 comments
Open

Function literal syntax improvements akin to Kotlin #342

natanfudge opened this issue May 5, 2019 · 0 comments

Comments

@natanfudge
Copy link

natanfudge commented May 5, 2019

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:

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:

if2(x > 4, x % 2 == 0, x < 10) {
  print(x);
  print(x + 2);
};

Note that this is very similar to a normal if statement:

if(x > 4) {
  print(x);
  print(x + 2);
}

If if2 accepted a function with 3 integer arguments we can perhaps write it like this:

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:

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:

if2(x,y,z){(a,b,c)=>
//
};

And then perhaps make brackets around the parameters optional:

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:

// If2 accepts 3 normal arguments and a function literal
if2(x,y,z), {
//
};
// 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:

exampleFunc {
  print("hello");
  print("world");
};

Take this real world example:

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:

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:

var list = [1,2,3];
var mapped = list.map((x) => x+2);

Or the new syntax:

var mapped = list.map {return it +2;}

Which is why I propose to remove the need to type return at all:

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:

// One statement
var mapped = list.map {it +2};
// 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:

// One statement
var mapped = list.map {it +2;};
// 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant