29

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?

Jéwôm'
  • 3,753
  • 5
  • 40
  • 73
gypsydave5
  • 542
  • 7
  • 15

1 Answers1

39

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.

yole
  • 92,896
  • 20
  • 260
  • 197
  • 3
    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. – gypsydave5 Jan 05 '18 at 11:21
  • 2
    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. – yole Jan 05 '18 at 11:23
  • 2
    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. – Chris Lercher Oct 24 '19 at 12:14
  • 1
    @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. – yole Oct 25 '19 at 10:46
  • This is the best answer which I found and make my day :) Thank you @yole – MrVasilev Mar 07 '22 at 20:37