Kotlin can’t choose
While giving a presentation on Kotlin’s lambdas, someone asked me a tough question. I actually had no idea how to answer it so I took that question home and gave it some thought. Now that I have finally answered it, I thought it would be good to share this question and its answer with everyone.
Let’s assume we have the following methods, how do you invoke one method over the other ?
The question explained
For those of you not familiar with Kotlin’s syntax, let’s take a step back and understand what the question actually is. We have declared two methods :
- one that receives an object and a lambda with no argument.
- another that receives an object and a lambda with receiver that will be called on the object received as first parameter (which we legitimately call “receiver”).
FYI : Those lambdas with receiver (sometimes also called lambda extension) are similar to extension functions.
If declared without the other one, we would call each method with code looking like this :
But, in our case, since there are 2 methods, Kotlin complains :
Alt+Enter will not help you with this choice. So, how can we call one method over the other ?
Calling the first method
The first thing I tried was to use
object like so :
As it turned out, it worked and I was able to call the first method.
You may be wondering what is
object in Kotlin. In short, they are a way to declare anonymous classes like we would in Java. I highly encourage you to read more about
object in the documentation in you are not familiar with it.
Using this solution, I’m creating an anonymous class of type
kotlin.jvm.functions.Function0 the same way Java would when calling this method from Java code.
Calling the second method
Confident from my first try, I thought may be I could call the second method with the following code :
But Kotlin doesn’t like that and complains again :
But, this time,
Alt+Enter gives us a solution :
OK but why ?
To better understand what happened, let’s take another step back and look at what happens when we create an extension function.
What Kotlin actually does is create a static method which receives the object as first parameters. This behavior is quite obviously exposed when calling a method extension (first snippet) from java code (second snippet) :
It is therefore understandable that if we were to call the second method in Java, we would need to create an anonymous class that receives the receiver as first parameter and this is exactly what we have done when calling the second method using
In case you were wondering, the anonymous class we have created is of type
There must be a better way
As we all know, Kotlin aims at being cleaner and shorted than Java. Using
object and overriding the
invoke method is a lot of boilerplate and feels too much like Java. There must be a better way.
Kotlin is actually a lot of fun, I mean, literally a lot of
fun and we can declare functions directly when calling methods :
This solution is actually better because we will be able to use
this inside the lambda with receiver (where
this represents the
String passed as first parameter) where we couldn’t using the
object solution. There is also a lot less boilerplate code and it’s much closer to Kotlin idioms.
Finally, another solution is to create the function and store it in a variable like so :
Although this works just as well, I would not recommend using it unless you want to re-use your lambda elsewhere as it decouples the code from the place where it is called for no good reason.
The problem came from the fact that Kotlin is very powerful but still fairly new for a lot of people. We are still getting used to its syntax and all the goodies it has in store for us.
Also, I like to take out of it, one more time, that every question is a chance to learn something new.