32

Kotlin has two ways of declaring an anonymous function (aka a lambda). The two different syntaxes are:

val lambda =  { input : String -> 
  "received ${input}"
}

and

val anonymousFunction =  fun (input : String): String {
  return "received ${input}"
}

I understand the difference between the two (as outlined in this answer), but what I don't understand is why the language has two different ways of declaring the same thing.

Are there optimizations at work under the hood for one verses the other? Was the anonymous function version thought to be too verbose? Could the lambda version of the syntax not support a return type?

1
  • 2
    The linked questions shows some advantages of anonymous functions in comparison to lambdas Commented Jan 5, 2018 at 11:05

1 Answer 1

43

The key reason is the support for returns from lambdas. The rule for returns is that the return keyword returns from the nearest function declared with the fun keyword. In some scenarios, you want a return in a block of code to return from the enclosing function, so you use a lambda:

fun processElements(list: List<Element>): Boolean {
     list.forEach { element ->
          if (!element.process()) return false   // returns from processElements()
     }
     return true
}

In other scenarios, you want to return from the block but not from the enclosing function. When using a lambda, returning from the block requires the return@label syntax, which is somewhat clunky:

fun processElements(list: List<Element>) {
     list.forEach { element ->
          if (!needToProcessElement(element)) return@forEach // returns from block
          element.process()
     }
}

To avoid the clunkiness, we've provided an alternative syntax - anonymous functions - which allows you to use return directly to return from the block:

fun processElements(list: List<Element>) {
    list.forEach(fun(element) { 
        if (!needToProcessElement(element)) return // returns from block
        element.process()
    })
}

A secondary reason is that it's indeed impossible to fit the return type declaration into the syntax of a lambda, but this is very rarely needed in practice, so it's not particularly important.

Sign up to request clarification or add additional context in comments.

5 Comments

So if I understand the above, the labelled return syntax for lambda was considered inelegant, and so the anonymous function syntax was introduced to allow for unlabelled early returns in blocks.
This is not how it happened historically over the course of evolution of pre-1.0 versions of Kotlin, but this is why we have two syntaxes in 1.0.
I assume, a more elegant solution could have been to have only lambdas, and always have the unlabeled return jump back to the direct caller of the lambda. So if you want to return further up, you'd have to specify that explicitly ("return@processElements"), as this is a statement with more of a "side-effect", from the labmda's point of view (normally it should only take arguments and return a result), and I feel that this should therefore be the situation that needs to be labeled explicitly. Having two semantics for the unlabeled return statement might be a source for easy mistakes.
@ChrisLercher The reason why Kotlin has the syntax it does is because we wanted lambdas to be a transparent replacement for control flow constructs (e.g. Kotlin doesn't have a synchronized statement as in Java because we wanted to implement it as a function) and we wanted return in such constructs to work in the same way as return in a Java synchronized block or for loop.
This is the best answer which I found and make my day :) Thank you @yole

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.