Home > other >  Why it's not possible to write extention function on Kotlin enum
Why it's not possible to write extention function on Kotlin enum

Time:12-07

I have the below code which works fine.

enum class Test() {
    TestOne,
    TestTwo
}

fun main() {
    Test.values().forEach{ item -> println(item) }
}

Output:

TestOne
TestTwo

Now I would like to create an extension function for the enum class receiver type Test to print those values like below

enum class Test() {
    TestOne,
    TestTwo
}

fun Test.printAllValues() {
    this.values().forEach{ item -> println(item) }
}

fun main() {
    Test.printAllValues()
}

But it throws a type ambiguity error.

Unresolved reference: values
Overload resolution ambiguity: public inline fun <T> Iterable<TypeVariable(T)>.forEach(action: (TypeVariable(T)) -> Unit): Unit defined in kotlin.collections public inline fun <K, V> Map<out TypeVariable(K), TypeVariable(V)>.forEach(action: (Map.Entry<TypeVariable(K), TypeVariable(V)>) -> Unit): Unit defined in kotlin.collections
Cannot infer a type for this parameter. Please specify it explicitly.
Overload resolution ambiguity: public inline fun println(message: Any?): Unit defined in kotlin.io public inline fun println(message: Boolean): Unit defined in kotlin.io public inline fun println(message: Byte): Unit defined in kotlin.io public inline fun println(message: Char): Unit defined in kotlin.io public inline fun println(message: CharArray): Unit defined in kotlin.io public inline fun println(message: Double): Unit defined in kotlin.io public inline fun println(message: Float): Unit defined in kotlin.io public inline fun println(message: Int): Unit defined in kotlin.io public inline fun println(message: Long): Unit defined in kotlin.io public inline fun println(message: Short): Unit defined in kotlin.io
Unresolved reference: printAllValues

CodePudding user response:

An extension function is defined such that the receiver is an instance of a class, not the name of a class. Inside your extension function, this is an instance of Test. You can't call values() on instances of an enum. It's a special function that is called on the name of the enum class. So, you have to call it as Test.values(), not this.values().

But, since you can only call it on an instance of a class, your syntax Test.printAllValues() will not work. You have to call your extension function on one of the instances of Test, such as Test.TestOne.printAllValues().

fun Test.printAllValues() {
    Test.values().forEach{ item -> println(item) }
}

fun main() {
    Test.TestOne.printAllValues()
}

In this case, that doesn't really make conceptual sense. To be able to define this extension function to work on the name Test, you need to give your enum a companion object, and you can define the function either as a member of this companion object, or as an extension on that companion. This takes advantage of the fact that the companion object's sole instance can be referred to by using the name of the class it is the companion of.

enum class Test() {
    TestOne,
    TestTwo;
    companion object {
        fun printAllValues() {
            Test.values().forEach{ item -> println(item) }
        }
    }
}

or

enum class Test() {
    TestOne,
    TestTwo;
    companion object
}

fun Test.Companion.printAllValues() {
    Test.values().forEach{ item -> println(item) }
}
  • Related