In Flutter there are lots of functions that only creates a Widget, like builders for example. All of those have a return statement.
I know we can omit the return using an => but still sometimes it's nice to have a lambda with () { }, instead of just =>.
Currently, if a function doesn't have a return it will return null by default.
I would like to propose that to be changed, so if no return is specified, then the last created object would be returned instead.
This way, this builder:
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
return Text('Hello');
}
Could be changed to:
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
Text('Hello');
}
I think this is too dangerous in practice, depending on how it's defined.
We will need to use the value of the expression of an expression statement.
We can take the last evaluated expression statement, or only an expression statement which is the last statement of the body, or any expression statement in "tail position".
Of these, "tail position" is the only realistic option, using "last evaluated" is too random and fragile, and "only last statement of body" is too restrictive.
A statement in tail position in another statement if, basically, there is no other statement executed after it, and no expression evaluated after it (so a loop body is not in tail position because the condition is evaluated after).
I still think this is a little too fragile.
If you write
(something) {
if (test(something)) bar(something);
}
it's not clear that the result of bar should be returned, but it will be.
So the return type of bar must be assignable to the inferred return type of the function literal (or worse, the return type of bar is used as the return type of the function literal). If bar is known to throw, then that static typing constraint is spurious.
The best way to avoid accidental constraints like that is to make returns explicit, so I don't think we'll allow you to omit return.
(something) {
if (test(something)) bar(something);
}
Hehe, and if the evaluation of test(something) yields false then _that_ is the most recently computed object, which will then be returned. ;-)
Oh, interesting, I thought it would be simpler, languages can be tricky for an "outsider", thanks for the attention :)
Maybe let would help in many of the cases that you have in mind? That would allow you to use a => function and still get the ability to compute a bunch of values and separate steps, and then return something based on that:
(something) =>
let var v1 = expression1;
var v2 = expression2;
in v1 + v2 end;
It won't do control structures (except of course that higher order functions like map and fold are semantically similar), but it will cover some of those situations where you would otherwise need to use a {}-bodied function.
PS: Languages are never simpler. ;-)
I think let could even help on another thing that bothers me a bit. In Flutter there are lots of constructors with named parameters, and sometimes I want to compute the parameter in place. If its a simple computation I can place it inside a ? : or ??, but if it's more complicated I need to make an external function for it and call it in place.
I was thinking about opening a proposal for having a way to define a lambda and call it at the same time to get its result in place, but let appears to do it.
Am I missing something and there's a way already to accomplish this? Or should I propose the lambda in-place execution anyway?
You can call a function literal using a plain (), that might suffice for those named arguments:
() { /*compute whatever you want here*/ return something; } ()
Great to know! Thanks Erik!
For the reasons mentioned, I don't think we are going to work towards this. Having to write a return is a small cost (even if it is a cost) in order to avoid ambiguities and accidents.
(Now, if return e could be written as, say, =>e or ^e then it would be shorter and still unambiguous. Not very readable, though, and might block other useful syntax).