- This is the 21st post in a multipart series.
If you want to read more, see our series index
Today we tackle a weird operator, invoke
which lets an instance of a class have a default function - which I am not sure I’ve ever seen any language do. So let us frame this with a simple example, we have a config class which returns the configuarion for something:
class Config {
fun get():String {
// do stuff
return "stuff"
}
}
fun main(args: Array) {
val config = Config()
println(config.get())
}
Now, in our world maybe get
is the primary use, so we can actually make it that the instance config (line 9) can be called to get it:
class Config {
operator fun invoke(): String {
return this.get();
}
private fun get():String {
// do stuff
return "stuff"
}
}
fun main(args: Array) {
val config = Config()
println(config())
}
Note that we add a new operator (line 2), and that calls the private get; it didn’t need to be private but I thought let us have this be cleaner, and now on line 14 we can just call the instance itself.
Now, you may be thinking… nice but so what saving a few keystrokes isn’t too awesome. Well, invoke can return anything, including itself which opens up something crazy.
class Config {
var count = 0;
operator fun invoke(): Config {
count++
return this
}
}
fun main(args: Array) {
val config = Config()
config()()()()()()()()()()
println(“config was called ${config.count} times”)
}
This will print out config was called 10 times
. That is getting more interesting, so let us ramp up another level and pass parameters to invoke
:
class Config {
var word = ""
operator fun invoke(s: String): Config {
word += s
return this
}
}
fun main(args: Array) {
val config = Config()
config(“R”)(“o”)(“b”)(“e”)(“r”)(“t”)
println(config.word)
}
While I do not know yet where I would use this myself, I do use invoke all the time… since it is what makes lambdas possible in Kotlin as when we create a lambda we get an object which is invoked with well… invoke.