Invocation syntax for functions accepting single argument lambdas
See original GitHub issueA very common scenario in many projects and libraries is one involving functions which accept a single argument, where the single argument is a zero- or single-argument function or lambda. In these cases, it would be useful to have a syntax which allows the body of the lambda directly in the function call’s braces without needing to wrap the lambda with additional curly braces, improving readability quite a bit.
The syntax would need to be able to disambiguate this usage from other possible usages of the named argument function invocation syntax.
To invent a fictional implementation as an example, one might be similar to the invoke operator but where the opening curly brace of the named argument invocation syntax is immediately followed by a colon, resulting in a new function invocation operator which opens with {:
as an indicator that the invocation braces directly contain the body (i.e. not wrapped in additional curly braces) of the single lambda argument being supplied.
{Integer*} ints = { 1, 2, 3 };
// 1.
ints.each((it) => print(it)); // today
ints.each {: print(it) }; // after - lambda statements directly in {: } invoke operator
// 2.
ints.map((it) { // today
print(it);
return it * 2;
});
ints.map {: // after - single param list ommitted
print(it);
return it * 2;
};
// 3.
ints.map((it) => it * 2); // today
ints.map {: => it * 2 }; // after - with fat arrow for explicit return
Basically:
- For single-argument lambdas, a special keyword (e.g.
it
) only available inside the lambda could be supported for accessing its single argument, and the need for an explicit parameter list relaxed. (Nested lambdas that would create nestedit
s or shadowedit
s could be disallowed). - When using the new syntax, relax the requirement for a terminating
;
at the end of the last statement or expression within the lambda block, as the ambiguity with other possible usages of the name argument syntax would not exist when using the new invoke operator. This will particularly eliminate the noise of the terminating semi-colon;
for lambdas with a single statement or expression. - For single expression lambdas that return a value, the fat arrow is used to satisfy explicit return.
- Finally, for multi-argument lambdas, which is not a primary use-case of this feature, the argument list could be between the opening curly
{
and the colon:
, surrounded by parentheses.
ints.sort((a, b) { // today
print("``a`` +");
print(b);
return a <=> b;
});
ints.sort {(a, b): // after
print(a);
print(b);
return a <=> b;
};
Issue Analytics
- State:
- Created 6 years ago
- Comments:68 (62 by maintainers)
Top GitHub Comments
I’m going to be the contrarian here, take this as you will:
I think friendly identifier names are unimportant for this feature. The identifiers will normally be used immediately, as they are in the majority of the examples, and with obvious meaning.
And, in fact, “standard” names like
it
or$0
(I know there are problems with the latter) actually highlight that the identifier is implicit, so you don’t have to read through a bunch of code to figure out which identifiers in an expression (or whatever) are the implicit ones.The names are not part of the type system, and are often different in method refinements.
Further, names chosen for documentation purposes which make sense for a particular function or method may be very confusing from the perspective of the caller’s code.
Hm, interesting… not sure about the look either, but I like the idea behind it very much. It gives a use to those parameter names besides documentation, it’s consistent, it lets you provide better names than
it
(I think I actually preferelement
overit
😃 ), and it supports functions with multiple parameters (great).