Kotlin / api-guidelines

Best practices to consider when writing an API for your library
https://kotl.in/api-guide
Apache License 2.0
145 stars 20 forks source link

Operator overloads as member or extension functions #22

Open LVMVRQUXL opened 11 months ago

LVMVRQUXL commented 11 months ago

Accordingly to the section Use member and extension functions appropriately, only properties, overrides and accessors should be members. But what about operator overloads?

For example, considering the following NotEmptyString class, if we would like to overload the plus operator for concatenating them, should we declare the overload as a member or as an extension function?

class NotEmptyString(private val value: String) {
    init {
        require(value.isNotEmpty()) { "String shouldn't be empty." }
    }

    /*
     * First case - member function.
     * The main advantage is that consumers don't have to import the function for using it.
     * We can also access declarations available only in that class.
     */
    operator fun plus(other: NotEmptyString): NotEmptyString = NotEmptyString(value + other.value)

    override fun toString(): String = value
}

/*
 * Second case - extension function.
 * This the way suggested by the Kotlin API guidelines to declare a function that is not part of the "very" core API
 * (because this is not an override, an accessor or a property of the receiver class).
 * But importing this operator function when writing 'NotEmptyString + NotEmptyString' feels less convenient...
 */
operator fun NotEmptyString.plus(other: NotEmptyString): NotEmptyString = NotEmptyString("$this$other")

fun main() {
    val hello = NotEmptyString("hello")
    val world = NotEmptyString(" world")
    println(hello + world) // hello world
}

Overloading operators may be an exception that should be declared as a member function...