I create a class and adds an extension to it with the same signature as a member function and executes this method it always executes member method.
class Worker {
fun work() = "...working"
}
fun Worker.work() = "...still working"
and I create an extension to String class for an already available method replace
and executes this replace
method; it invokes extension method instead and give Hell as output.
fun String.replace(oldValue: String, newValue: String, ignoreCase: Boolean = false): String = this.substring(0, this.length - 1);
then
fun main(args: Array<String>) {
val worker = Worker()
println(worker.work()) // output: ...working
val myString= "Hello"
val result1 = myString.replace("Hello", "Bye")
println("First character is: $result1") // output: First character is: Hell
}
what is that I am missing? I was expecting replace would give Bye as output.
val myString= "Hello"
val result1 = myString.replace("Hello", "Bye")
println("First character is: $result1") // output: First character is: Bye
How String works in Kotlin with Extension?
Note that the existing replace
function in the standard library is also an extension function, declared in the kotlin.text
package.
fun String.replace(oldChar: Char, newChar: Char, ignoreCase: Boolean = false): String
You are able to access it because kotlin.text
is implicitly imported.
Because both your replace
and the existing replace
are extension functions, but the existing replace
is implicitly imported, overload resolution chooses your replace
.
The exact priorities are described in the language specification:
If a call is correct, for a callable f with an explicit receiver e of type T the following sets are analyzed (in the given order):
- Non-extension member callables named f of type T;
- [...]
- [...]
- Extension callables named f, whose receiver type U conforms to type T, declared in the package scope;
- [...]
- Implicitly imported extension callables named f (either from the Kotlin standard library or platform-specific ones), whose receiver type U conforms to type T.
[...]
When analyzing these sets, the first set which contains any applicable callable is picked for c-level partition, which gives us the resulting overload candidate set.
Set 6 contains the existing replace
in the standard library. Set 4 contains the replace
and work
extensions that you have declared. Set 1 contains the work
method declared in Worker
.
Because of this order in which Kotlin looks up a name, you see different results depending on where the original function is declared and how it is imported.