why can I override String.toUpperCase() but not St...
# announcements
s
why can I override String.toUpperCase() but not String.toString() via an extension function?? I’m not surprised that I get a warning that my toString-extension is shadowed, but why isn’t that the case with toUpperCase? https://pl.kotl.in/Fqwewe9CL
Copy code
fun main() {
    val result: String = "xY"
    println("${result.toUpperCase()}-${result.toString()}")
}

fun String.toUpperCase() = "overridde_toUpperCase"
fun String.toString() = "overridde_toString"
leads to output
overridde_toUpperCase-xY
p
You can not override methods that exists on the object
Copy code
/**
 * The root of the Kotlin class hierarchy. Every Kotlin class has [Any] as a superclass.
 */
public open class Any {
    /**
     * Indicates whether some other object is "equal to" this one. Implementations must fulfil the following
     * requirements:
     *
     * * Reflexive: for any non-null value `x`, `x.equals(x)` should return true.
     * * Symmetric: for any non-null values `x` and `y`, `x.equals(y)` should return true if and only if `y.equals(x)` returns true.
     * * Transitive:  for any non-null values `x`, `y`, and `z`, if `x.equals(y)` returns true and `y.equals(z)` returns true, then `x.equals(z)` should return true.
     * * Consistent:  for any non-null values `x` and `y`, multiple invocations of `x.equals(y)` consistently return true or consistently return false, provided no information used in `equals` comparisons on the objects is modified.
     * * Never equal to null: for any non-null value `x`, `x.equals(null)` should return false.
     *
     * Read more about [equality](<https://kotlinlang.org/docs/reference/equality.html>) in Kotlin.
     */
    public open operator fun equals(other: Any?): Boolean

    /**
     * Returns a hash code value for the object.  The general contract of `hashCode` is:
     *
     * * Whenever it is invoked on the same object more than once, the `hashCode` method must consistently return the same integer, provided no information used in `equals` comparisons on the object is modified.
     * * If two objects are equal according to the `equals()` method, then calling the `hashCode` method on each of the two objects must produce the same integer result.
     */
    public open fun hashCode(): Int

    /**
     * Returns a string representation of the object.
     */
    public open fun toString(): String
}
toString
exists on type
Any
which all objects inherit from thus you can not override it.
toUpperCase
does not exist.
s
but toUpperCase() exists on String!
r
String.toUpperCase()
is an extension function.
String.toString()
is a method.
Copy code
public actual inline fun String.toUpperCase(): String = (this as java.lang.String).toUpperCase()
j
String.toUpperCase is defined as an extension function on String, at
org.jetbrains.kotlin/kotlin-stdlib/1.3.21/b8815e48fb45e94821287365bd9ce8623f459ac7/kotlin-stdlib-1.3.21-sources.jar!/kotlin/text/StringsJVM.kt
p
You can "override" other extensions but not members. By "override" I mean you can include extensions from different packages so technically you are not overriding anything but adding a new extension that exists in a different package.
s
but String.toUppercase already exists on the Java-base type.
j
I guess Kotlin doesn't consider that on the base. the JVM string functions are extensions to the Kotlin String class
p
Kotlin String does not contain that method.
Copy code
/**
 * The `String` class represents character strings. All string literals in Kotlin programs, such as `"abc"`, are
 * implemented as instances of this class.
 */
public class String : Comparable<String>, CharSequence {
    companion object {}
    
    /**
     * Returns a string obtained by concatenating this string with the string representation of the given [other] object.
     */
    public operator fun plus(other: Any?): String

    public override val length: Int

    /**
     * Returns the character of this string at the specified [index].
     *
     * If the [index] is out of bounds of this string, throws an [IndexOutOfBoundsException] except in Kotlin/JS
     * where the behavior is unspecified.
     */
    public override fun get(index: Int): Char

    public override fun subSequence(startIndex: Int, endIndex: Int): CharSequence

    public override fun compareTo(other: String): Int
}
s
ok, that kind of explains that, but if you have control over the class (kotlin.String), why is toUpperCase added as extension function then??
p
Only kotlin devs can answer that but I think there is no need to clutter the String class with those kind of methods so they added them as extensions.
s
it’s not like it makes any difference to autocomplete (where the real cluttering occurs). I assumed that extension functions are only for extending the functionality of classes you don’t have control over but this usage in that std lib implies that there are other reasons.
p
Maybe it is because of multiplatform? To keep the base classes lean.
s
sounds like a possibility. I just feels strange that I can seemingly monkey-patch widely used methods like toUpperCase(). Definitely a Kotlin puzzler 😆
d
monkey patching is done in run time, while kotlin extension functions are compile time, don't think it's comparable
r
Would using the same pattern on my own classes be recommended? i.e. Simpler classes and using extension functions for the majority of the functionality?
r
@Stephan Schroeder You should read @elizarov's article about that: https://medium.com/@elizarov/extension-oriented-design-13f4f27deaee
💯 1
r
Great read. Thanks @Ruckus
👍 1
s
@Ruckus thank you for the non-trivial revelation 👍
👍 1