Search code examples
kotlinextension-methods

Extension to String in Kotlin


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?


Solution

  • 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):

    1. Non-extension member callables named f of type T;
    2. [...]
    3. [...]
    4. Extension callables named f, whose receiver type U conforms to type T, declared in the package scope;
    5. [...]
    6. 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.