...

/

Fluency with Any Object

Fluency with Any Object

infix reduces some noise, but when working with just about any object, Kotlin makes code less verbose and more expressive. The language does this by adding a few convenience functions. Learning those methods can make your everyday coding a pleasant experience and make your code more fluent.

Coding in Kotlin involves invoking functions, methods, and passing lambda expressions, among other things. The language offers some support for minimizing noise with these day-to-day operations.

Specifically, Kotlin has four significant methods that can make code fluent: also(), apply(), let(), and run(). Each of these methods takes a lambda expression as a parameter and returns something back after invoking the given lambda. The format of a call to one of these methods, on a context object, looks like this:

result = context.oneOfTheseFourMethods { optionalParameter -> 
        ...body...
        ...what's this (receiver) here?... 
        optionalResult
}

Depending on the method you call, the optionalParameter and this, the receiver of the call, will be assigned differently. The optionalResult received from the call will differ as well. Once we learn a bit more about these functions, we’ll see how we can benefit from these functions to create concise and expressive code. Stay tuned.

Behavior of the four methods

Let’s exercise these four methods and report back on the arguments received by the lambdas passed, the this receiver within each lambda expression, the result returned by them, and the result received on the calling side of these four methods.

Press + to interact
val format = "%-10s%-10s%-10s%-10s"
val str = "context"
val result = "RESULT"
fun toString() = "lexical"
println(String.format("%-10s%-10s%-10s%-10s%-10s",
"Method", "Argument", "Receiver", "Return", "Result"))
println("===============================================")
val result1 = str.let { arg ->
print(String.format(format, "let", arg, this, result))
result
}
println(String.format("%-10s", result1))
val result2 = str.also { arg ->
print(String.format(format, "also", arg, this, result))
result
}
println(String.format("%-10s", result2))
val result3 = str.run {
print(String.format(format, "run", "N/A", this, result))
result
}
println(String.format("%-10s", result3))
val result4 = str.apply {
print(String.format(format, "apply", "N/A", this, result))
result
}
println(String.format("%-10s", result4))

Each of the lambdas ends with an expression result, but some of them may get ignored, as we’ll see. The first two lambdas receive a parameter arg and the last two don’t. Study the output to learn about the behavior of the methods:

Method    Argument  Receiver  Return    Result    
===============================================
let       context   lexical   RESULT    RESULT    
also      context   lexical   RESULT    context   
run       N/A       context   RESULT   
...