Kotlin scope functions
13 Feb 2019 | kotlinI have been working with Kotlin recently and really enjoying it compared to Java.
A really useful feature is the ability to define extension functions on existing classes.
The built-in scope functions let, run, also, apply and with are really handy
and are described well in
Coping with Kotlin scope functions.
It can be difficult to remember which one to use. It helps me to think first of whether the function returns the receiving object or the value of the lambda.
Return the receiver
The functions also and apply return the receiver. For example, here is a natural way to get a
Jackson object mapper and configure it in one expression:
val mapper = jacksonObjectMapper().apply {
    configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
    configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, false)
}
Within the lambda, this is set to the object returned by jacksonObjectMapper().
Similarly, also returns the receiver and passes it to the lambda as an argument instead
of as self. This feels natural for side-effects that do not change the receiver, like logging:
return serviceResponse.also {
    log.info("Returning service response: $it")
}
Return the value of the lambda
The functions let, run and with return the lambda. They can be used as idiomatic
null checks, for example:
val result = value?.let { transform(it) } ?: defaultValue
This has the meaning, If value is not null, transform it; else return a default
value.
run is similar, except that it applies directly to the receiver (available as this in
the lambda).
There is a with function like that in Visual Basic, except that it returns the value of
the lambda (which can be ignored).
with(something) {
    setValue(newValue)
}
Quick mnemonic
- If the scope function starts with a (also,apply) it returns the receiver;
- else (let,run,with) it returns the lambda.