Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fat Arrow notation with curly braces in setState Dart/Flutter

Tags:

flutter

dart

I am very new to Dart/Flutter and I have a confusion regarding the => notation. The documentation says that the => notation is used as a shorthand to return a single expression.

bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;

My doubt comes when I am trying to set state in a flutter application.

RaisedButton(
  onPressed: () => {
    setState(() {
      print('hello');
      _products.add('More stuff');
    })
  },
  child: Text('Add Product'),
),

Now when i change the setState method with => notation

RaisedButton(
  onPressed: () => {
    setState(() => {
      print('hello'),
      _products.add('More stuff'),
    })
  },
  child: Text('Add Product'),
),

Both methods mentioned above work, that is they set the state as expected. All i had to do was change the semicolons to commas when using the fat arrow notation.

What is the logic behind this ? How is the fat arrow notation working with curly braces which contains multiple expressions within it.

Edit

As mentioned by Hemanth Raj the => returns a set and the code segment containing the => notation can be written as follows.

RaisedButton(
  onPressed: () => {
    setState(() {
     return {
       print('hello'),
       _products.add('More stuff'),
     };
    })
  },
  child: Text('Add Product'),
),

How is the returned set containing a print function and _products.add actually updating the state. Shouldn't it throw some kind of error because usually setState is done by an expression such as _products.add('More stuff');.

like image 561
Muljayan Avatar asked Mar 26 '19 06:03

Muljayan


2 Answers

This is one of the interesting questions that I would love to answer.

As the official documents say here, yes => is used as a shorthand syntax to { return ... } which means => will just return whatever is produced on the righthand side.

Also from Dart 2.2 and above, a Set can be defined with comma separated values enclosed in a {} as mentioned in docs here.

Hence, the syntax you are using, i.e {} with statements separated with a comma, it is treated as a Set by the => functions. Each element being a function call, () => { f(a) , f(b), g(a),} would return a Set with the elements returned by each function call.

This example might help you understand what is happening under the hood:

dynamic reflect(dynamic a){
  return a;
}

void main() {  
    Function shortHand = () => {reflect(1),reflect('a'),reflect({}),reflect([]),}; // this function when called will return a Set<dynamic>
    print(shortHand().runtimeType); // will print `_LinkedHashSet<dynamic>`
}

So the syntax

() => '...' returns a String,

() => [ ... , ..., ...] returns a List

and similarly () => { ... , ... , ... } actually returns a Set

Note: This method of returning set with comma separated function calls is not recommended, would request you also not to use it unless you wanted a Set to be returned as result


Reply to the Edit :

Let me breakdown the function call and results for you. So your code goes like this,

() => {
    setState(() {
     return {
       print('hello'),
       _products.add('More stuff'),
     };
    })
  }

Here the => returns a Set with the result of setState, i.e it'll return { (result of setState call) } which might be { null }

As you have call setState the below code gets executed, which again returns a Set with { (result of print), (result of _product.add), }

() {
      return {
        print('hello'),
        _products.add('More stuff'),
      };
    }

State will update, as you are executing _products.add('More stuff'), where 'More stuff' will be added to _products irrespective of where you call it. When setState is being called, the widget will be rebuilt with the _products with new data added.

Hope this helped!

like image 188
Hemanth Raj Avatar answered Sep 24 '22 21:09

Hemanth Raj


For the record, the recommended syntax for what you are doing is:

RaisedButton(
    onPressed: () {
      setState(() {
        print('hello');
        _products.add('More stuff');
      });
    },
    child: Text('Add Product'),
),

The syntax (args) => { statements } is not how Dart writes function bodies, you do either (args) { statements } or (args) => singleExpression.

Also, you need to terminate statements with semicolons, ;, not commas.

As others have pointed out, the syntax you use (args) => { print("something"), somethingElse } is actually creating a set (a Set<void> because the return type of print is void) and returning that.

This is a perfect storm of small syntax mistakes, which would seem reasonable to a JavaScript programmer, that comes together to actually mean something completely different in Dart. And, just to make things even worse, the code works. The set literal will evaluate its expression in order, and nobody sees the created set anyway. The syntax just doesn't generalize — you can't change any of the expressions to, say, a for-loop (yet, you will be able to in the next version of Dart).

So, in Dart, never use => { unless you want to return a set or map.

like image 23
lrn Avatar answered Sep 25 '22 21:09

lrn