- Type: Design proposal
- Author: Andrey Breslav
- Status: Implemented in Kotlin 1.1
- Discussion: KEEP-32
Support destructuring declarations in parameters of lambdas.
NOTE: Support in parameters of functions (declarations and expressions), constructors and setters will be discussed for future-proof design, but is not proposed to be implemented at this time.
To be supported now:
// decomposing pairs in a lambda
listOfPairs.map {
(a, b) -> a + b
}
May be supported later:
// decompose a parameter:
fun foo((a, b): Pair<Int, String>, c: Bar)
// can be called as
foo(pair, bar)
// decompose a constructor parameter
class C(val (a, b): Pair<Int, String>) {}
We allow parentheses in lambda parameter lists:
In Kotlin 1.0 the syntax for a lambda is:
functionLiteral
: "{" statements "}"
: "{" (SimpleName (":" type)?){","} "->" statements "}"
;
Here we propose to extend it:
functionLiteral
: "{" statements "}"
: "{" lambdaParameter{","} "->" statements "}"
;
lambdaParameter
: variableDeclarationEntry
: multipleVariableDeclarations (":" type)?
;
// already defined, shown for reference
variableDeclarationEntry
: SimpleName (":" type)?
;
multipleVariableDeclarations
: "(" variableDeclarationEntry{","} ")"
;
Note: while modifiers in front of lambda parameters are mentioned in the grammar for 1.0, they are not actually supported by the parser. If we ever support modifiers here, we should allow them in front of individual components, but for now, the actual rule should be without them
Examples:
{ a -> ... } // one parameter
{ a, b -> ... } // two parameters
{ (a, b) -> ... } // a destructured pair
{ (a, b), c -> ... } // a destructured pair and another parameter
Question: Should we support nested destructuring for parameters?
{ ((a, b), c) -> ... } // a destructured pair whose first component is a pair
> NOTE: this is not supported for destructuring val's and var's
A type may be specified for the whole destructured parameter, for its individual components (independently), or both:
``` kotlin
{ (a, b: B) -> ... }
{ (a, b): Pair<A, B> -> ... }
{ (a: A, b): Pair<A, B> -> ... }
Note: no changes to the syntax of function types is needed since the syntax for call sites (where a lambda is invoked) is not changed.
Semantically, destructured parameters work as if they are normal parameters and a destructuring assignments are performed before the body of the lambda, in the left-to-right order:
{
(a, b), (c, d) ->
body()
}
is translated to
{
_p1, _p2 ->
val (a, b) = _p1
val (c, d) = _p2
body()
}
Typing rule: Types of the components must be compatible with component-functions (componentN()
) resolvable on corresponding parameters. When such functions can not be applied or their return types are not assignable to declared types of components, an error is reported.
Component-functions are resolved in the same scope as the first statement of the lambda. The reason is that we want to preserve desugaring semantics described above.
But the following example still must not compile because the relevant parameters are not and cannot be marked as operators.
{
component1: P.() -> A,
component2: P.() -> B,
(a, b): P // error: component functions not resolved
->
...
When type inference is concerned with the shape of a lambda, a destructured parameter acts as a normal one (single), and its type may be used if declared. Types of components do not affect type inference even when specified: there's no way to know what type would be destructured into the given component types.
Naming rule: all names declared in a parameter list of the same lambda (normal parameters and components of destructured ones) must be unique, i.e. this is an error: { (a, b), a -> ... }
- Intention actions for lambda parameters:
- introduce destructuring
- collapse destructuring
- Inspection to detect a manual destructuring, e.g.:
{
val (a, b) = it
...
}
-
- a quick-fix to replace this with
{ (a, b) -> ... }
- a quick-fix to replace this with
- Actions to transform a for-loop into map/fiter/... should now support transferring destructured variables between
for
and lambdas. - Adjustments may be needed in Change signature for lambdas