For a practical example read above, I try to do it a bit more theoretical.
An approach to decipher difficult lambda’s…
(Two times the same story, but the Java-one is for if you know Java and is not really documented)
If you do understand Java functional interfaces
(Int) -> Unit
// roughly the same as
Consumer<Int>
(Int) -> Int
//roughly the same as
Function<Int, Int>
(Int, Int) -> Int
//roughly the same as
BiFunction<Int, Int, Int>
((Int, Int) -> Int)?
// roughly the same as
(BiFunction<Int, Int, Int>)?
// roughly the same as
BiFunction<Int, Int, Int>? //type with question mark, so nullable.
(Int) -> ((Int) -> Unit)
//roughly the same as
(Int) -> (Consumer<Int>)
//roughly the same as
Function<Int, Consumer<Int>>
((Int) -> (Int)) -> Unit
//roughly the same as
(Function<Int, Int>)-> Unit
//roughly the same as
Consumer<Function<Int, Int>>
(Kotlin doesn’t use the functional interfaces but it’s own, so it’s roughly the same.)
(Int)->Unit //takes an Int, returns Unit
(Int)->Int //takes an int, returns an Int
(Int, Int) ->Unit //takes 2 Integers, returns Unit
In Kotlin we can create typealiases, other names for types.
A lambda is a type, so we can give it another name.
Let’s do it:
typealias IntConsumer = (Int) -> Unit //takes an int, return Unit
typealias IntChanger = (Int) -> Int //takes an int, returns an Int.
typeAlias IntCombiner = (Int, Int) -> Int //takes two ints, returns an Int
now let’s rewrite your function using our created typealiases:
((Int, Int) -> Int)?
/*. |---------------| is our IntCombiner */
(IntCombiner)?
//which is the same as
IntCombiner?
In other words, if we have a variable with the type IntCombiner
, the variable cannot be null
.
If we have a variable with the type IntCombiner?
it can be null
.
So, it just means it can be either a lambda which takes two Ints and returns one Int, or it can be null.
ok, up to the next
(Int) -> ((Int) -> Unit)
/* |-----------| is our IntConsumer */
(Int) -> (IntConsumer)
//which is the same as
(Int) -> IntConsumer
This means it takes an Int and returns our IntConsumer.
((Int) -> (Int)) -> Unit
/* |------------| is our IntChanger */
( IntChanger ) -> Unit
This means it takes our IntChanger and returns Unit
if you rewrite and there are no (), you start rewriting from the right.
This brings us to the last example
(Int) -> (Int) -> Unit
// is this
(Int) -> IntConsumer
// or is it
(IntChanger) -> Unit
If you start rewriting from the right, you come to the answer:
(Int) -> IntConsumer
//or written out:
(Int) -> (Int -> Unit)
//or in words, takes an int, returns a lambda that takes an int and returns nothing.