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.