Why not support function deconstruction, but support lambda expression deconstruction

val df={(name,pass):MyUser-> name }

fun good((name,pass):MyUser){

1 Like

I think it makes more sense for lambdas, because:

  • They should be as short as possible,
  • In most cases, we don’t really control what parameters our lambda receives - parameters are provided to us and we need to deal with them.

The second reason is probably the main one. If you need to receive name and pass separately to your function then why won’t you declare it as?

fun good(name: String, pass: String)

It is even more useful, because it doesn’t require your caller to have a special MyUser object - it has less requirements to use it. Lambdas are different, some API was designed in the way that it provides you with MyUser and you can’t say you would like to receive user and pass separately. Well… you can, with destructuring it.

Similar question would be: why can we use “_” for unused param in lambdas, but we can’t do this with regular functions? But what is the point of introducing unused parameter in the first place?

One exception to what I said above is overriding/implementing a function. In that case we can’t control parameters, but I think that changing anything in the function signature when overriding would be messy. Even changing the name of the parameter is discouraged. Also, see my first point: it doesn’t make too much sense to e.g. rename unused params to “_”, because we don’t need to make overrides as short as possible.

1 Like

Functions and lambdas are inherently different in that a function declares an API surface, a lambda is only an implementation.

I imagine the limitation for functions is somewhat tied to named arguments.

You can call any Kotlin function with named arguments because Kotlin requires function parameters to have names. Function types on the other hand have no parameter names and you cannot call them with named arguments.

Lambdas can implement SAM interface functions or function types. In either case, the lambda itself has no effect on what’s allowed for the caller but rather it is the API that the lambda is implementing that matters. This affords it a lot more freedom without having any impact on callers.

A function type example:

val f: (Int) -> Int = { it + 1}
println(f(3)) // Can't call function types with argument names

SAM example:

fun interface Incrementer {
    fun increment(value: Int): Int
val i = Incrementer { it + 1 }
println(i.increment(value = 3)) // Function, not lambda, affects argument name