Lambdas

function types

Kotlin support function types. Values of that types can be anonymous functions, lambdas or reference to the class method.

To declare function type you list types of parameters in parentheses and after arrow specify return type like (A, B) -> C.

The parameter types list may be empty, as in () -> A.

Unlike functions, the Unit cannot be omitted: () -> Unit.

Optionally, parameters can be named: (x: Int, y: Int) -> Point.

// create alias
typealias ClickHandler = (Button, ClickEvent) -> Unit

// assign reference to the method of current class
var clickHandler: (Button, ClickEvent) -> Unit = ::onClick;

// assign reference to the method of object
var clickHandler: (Button, ClickEvent) -> Unit = view::onClick;

// assign anonimous function
var clickHandler: (Button, ClickEvent) -> Unit = fun (bt: Button, event: ClickEvent){
    // do something
}

// assign lambda expression
val l : (Int, String) -> String = {a: Int, s: String ->
            val b = a*a
            s+" "+b 
        }

// in lambda types of parameters can be omitted
val l2 : (Int, String) -> String = {a, s ->
            val b = a*a
            s+" "+b 
        }

lambda expression

Lambdas are always declared in curly braces. At begin you specify list of parameters, then the arrow then the body of lambda.

It is allowed not to declare the only parameter and omit ->. In this case the parameter will be implicitly declared under the name it.

You can explicitly return a value from the lambda using the qualified return syntax. Otherwise, the value of the last expression is implicitly returned, unless the return type is Unit.

// filter method accept (it: Int) -> Boolean argument
ints.filter {
    val shouldFilter = it > 0
    shouldFilter
}

ints.filter {
    val shouldFilter = it > 0
    return@filter shouldFilter
}

higher-order function

A higher-order function is a function that takes functions as parameters, or returns a function.

if the last parameter of a function is a function, then a lambda expression passed as the corresponding argument can be placed outside the parentheses. Such syntax is also known as trailing lambda.

If the lambda is the only argument to that call, the parentheses can be omitted entirely.

You can call lambdas via the invoke() method or operator ()

fun filter(f : (it: Int) -> Boolean){
    // .. do something
    val b = f.invoke(34)
    val c = f(34)
}

// calling filter function, any syntax are correct
filter { it%2==0 }

filter(){
    it%2==0 
}

filter{ anotherName ->
    anotherName%2==0
}

filter({it -> it%2==0 })

closure

A lambda expression / anonymous function / local function / object expression can access its closure, which includes the variables declared in the outer scope. The variables captured in the closure can be modified.

inline

The inline modifier allows to inline the function itself and the lambdas passed to it into the call site. It is useful because closures cause memory allocations and virtual calls introduce runtime overhead.

// lock is inline function
lock(l) { foo() } 

// this call will generate following code
l.lock()
try {
    foo()
} finally {
    l.unlock()
}

noinline allows you to specify which lambda argument should not be inline.

inline fun foo(inlined: () -> Unit, noinline notInlined: () -> Unit) { ... }

Inlining may cause the generated code to grow; however, if you do it in a reasonable way (avoiding inlining large functions), it will pay off in performance, especially at "megamorphic" call-sites inside loops.

functional interface

You can declare a single abstract method (SAM) interface as a functional interface. This allows you to convert the interface to a lambda and vice versa.