Learning Kotlin: Invoke

Submitted by Robert MacLean on Thu, 08/16/2018 - 09:00
**More Information** * This is the 21st post in a multipart series. If you want to read more, see our [series index](/learning-kotlin-introduction) 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<String>) {     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<String>) {     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<String>) {     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<String>) {     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.