Kotlin — The power of lambdas
In my previous post I explained how to replace listeners with lambdas, but didn’t talk too much about lambdas themselves. Today i’ll talk about a couple of things that make kotlin lambdas really powerful.
You’ll see lambdas in many places in kotlin, (not just as in a listener replacement), as many instructions rely on lambdas for fulfilling their purpose.
Lambdas are an anonymous portion of logic that are executed when they are required, which are commonly referred to as a block (which is how i’ll refer to them from now on).
- A block is a function literal, with its own type, this means we can store them as properties
var myBlock: (Int) -> Unit = …
- A block could be optional as any other property in kotlin
var myBlock: ((Int) -> Unit)? = null
- A block body infers parameters and return types based on context and the last execution line
var myBlock: (Int) -> String = { theInt -> theInt.toString() }
var myBlock = { theInt: Int -> theInt.toString() }
- A block body with a single parameter doesn’t need to have it named, instead you can access the values with the default name
it
var myBlock: (Int) -> String = { it.toString() }
- A block with a parameter of the types
Pair
orMap
could split the elements in it’s body declaration(since kotlin 1.1)
var myBlock: (Pair<*,*>) -> Unit = { firstValue, secondValue -> … }
var myBlock: (Pair<*,*>, Int) -> Unit = { (firstValue, secondValue), intValue -> … }
With these basic concepts you can start creating your own blocks, so let’s dive a little bit deeper.
As I mentioned previously, blocks infer the return value and they ALWAYS have a return value, which means that any instruction that uses a block will return a result value.Lambdas are everywhere in kotlin, an if else
uses blocks, when
also uses blocks and they benefit from this, cause they can return a value.
var result = if (value > 10) “more than 10” else “less than 10”
or
var result = (if (value > 10) “more” else “less”) + “ than 10”
in a when
statement things get more interesting as each case has its own block and the value being checked is casted for you automatically.
var anyValue: Any = 7 //note that we are specifying the type as Anyvar result = when(anyValue) {
is Int -> { “${anyValue.toString()} is integer” }
is Double -> { “${anyValue.toString()} is double” }
is String -> { “$anyValue is string” }
else -> { “we don’t know the type of anyValue” }
}
This is extra powerful when using sealed classes, which are like enums on steroids, you can check for the different types in a when
statement and have them casted to the one you need, after that you can access the state of the element you checked
sealed class MyPowerClass
data class DataFromCodelitt(val remote: Map<String, Any>?, val received: Boolean): MyPowerClass()
data class LocalData(val local: Map<String, Any>): MyPowerClass()val result = when(data){
is DataFromCodelitt -> if(received) data.remote?.toString() else
“no data”
is LocalData -> data.local.toString()
}