'Invoke Operator & Operator Overloading in Kotlin
I get to know about the Invoke operator that,
a()
is equivalent to a.invoke()
Is there anything more regarding Invoke operator than please explain. Also, I did not get any example of Invoke operator overloading.
Is Invoke operator overloading possible? If possible then can anyone please explain about the Invoke operator overloading with an example? I did not get anything regarding this.
Thanks in advance.
Solution 1:[1]
Yes, you can overload invoke
. Here's an example:
class Greeter(val greeting: String) {
operator fun invoke(target: String) = println("$greeting $target!")
}
val hello = Greeter("Hello")
hello("world") // Prints "Hello world!"
In addition to what @holi-java said, overriding invoke
is useful for any class where there is a clear action, optionally taking parameters. It's also great as an extension function to Java library classes with such a method.
For example, say you have the following Java class
public class ThingParser {
public Thing parse(File file) {
// Parse the file
}
}
You can then define an extension on ThingParser from Kotlin like so:
operator fun ThingParser.invoke(file: File) = parse(file)
And use it like so
val parser = ThingParser()
val file = File("path/to/file")
val thing = parser(file) // Calls ThingParser.invoke extension function
Solution 2:[2]
The most way to use a invoke operator is use it as a Factory Method, for example:
// v--- call the invoke(String) operator
val data1 = Data("1")
// v--- call the invoke() operator
val default = Data()
// v-- call the constructor
val data2 = Data(2)
This is because the companion object is a special object in Kotlin. Indeed, the code Data("1")
above is translated to the code as below:
val factory:Data.Companion = Data
// v-- the invoke operator is used here
val data1:Data = factory.invoke("1")
class Data(val value: Int) {
companion object {
const val DEFAULT =-1
// v--- factory method
operator fun invoke(value: String): Data = Data(value.toInt())
// v--- overloading invoke operator
operator fun invoke(): Data = Data(DEFAULT)
}
}
Solution 3:[3]
Operator Function invoke() Kotlin provides an interesting function called invoke, which is an operator function. Specifying an invoke operator on a class allows it to be called on any instances of the class without a method name.
Let’s see this in action:
class Greeter(val greeting: String) {
operator fun invoke(name: String) {
println("$greeting $name")
}
}
fun main(args: Array<String>) {
val greeter = Greeter(greeting = "Welcome")
greeter(name = "Kotlin")
//this calls the invoke function which takes String as a parameter
}
A few things to note about invoke() here. It:
- Is an operator function.
- Can take parameters.
- Can be overloaded.
- Is being called on the instance of a Greeter class without method name.
Solution 4:[4]
If you have some Python background,
you can think invoke
in Kotlin as __call__
in Python.
By using this, you can "call" your object as if it's a function.
One difference is: you can overload invoke
, but there is no official way to overload methods in Python.
Solution 5:[5]
In addition to the other answers:
It's possible to define a class extending an anonymous function.
class SpecialFunction : () -> Unit {}
In such case, the operator invoke
is already defined, so it needs to be overriden:
class MyFunction : () -> Unit {
override fun invoke() { println("Hi Mom") }
}
One more thing about syntax repercussions:
If such "functor" is called right after constructing it, you end up with double parentheses:
MyFunction()()
And, if such functor returns another functor, you may see some obscurities like
MyFunction()()()()()...
perhaps including parameters. This will not surprise anyone coming from the JavaScript world, though.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | |
Solution 3 | Daniil Laureanti |
Solution 4 | starriet |
Solution 5 | Ondra Žižka |