Read on for a description of the also()
and apply()
scope functions in Kotlin.
The also
function
The definition of also
is essentially this:
//sampleStart inline fun <T> T.also(block: (T) -> Unit): T { block(this) return this } //sampleEnd fun main() { val poem = """ Kotlin, the architect of code's stronghold, With extension properties, it's a tale told. From towers to ramparts, a structure so grand, In the world of languages, it takes a stand! """.trimIndent() println(poem) }
If this seems familiar, it is because you wrote your own version in a previous lesson.
From a purely practical standpoint, what this allows you to do is to execute a side-effect (i.e. a block of code that does not return anything = Unit
) and then continue working with the receiver.
We talked about one possible use, which was logging information inside a longer call chain:
//sampleStart val someOtherProp = obj.someProp.someMethod().also { log(it) }.someOtherProp //sampleEnd
You could easily get by just by declaring an extra variable:
//sampleStart val someMethodResult = obj.someProp.someMethod() log(someMethodResult) val someOtherProp = someMethodResult.someOtherProp //sampleEnd
However, not only does also
save you some keystrokes, but in some situations can lead to more elegant code by compressing it into a single expression. That can come in handy when defining a function as an expression.
But don't forget - shorter/more concise is not always better! Prioritize readability over everything else.
The apply
function
apply
functionThe definition of apply
is essentially:
//sampleStart inline fun <T> T.apply(block: T.() -> Unit): T { block() return this } //sampleEnd fun main() { val poem = """ Kotlin, the architect of code's stronghold, With extension properties, it's a tale told. From towers to ramparts, a structure so grand, In the world of languages, it takes a stand! """.trimIndent() println(poem) }
When you compare apply
with also
, you'll come to the startling realization that they are practically identical - the only difference is that also
uses the receiver as a parameter to block
, while apply
uses it as a receiver.
From a functional standpoint, the following are completely equivalent:
//sampleStart class A { fun doStuff() { // Stuff } } A().also { it.doStuff() } A().apply { doStuff() } //sampleEnd
So when should you use which, and more importantly, why? Read on to find out.