Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can I not call .values() on generic enum class?

I know that calling .values() on an enum class gives an array of the enum cases. However it doesn't work with a generic enum class. Why is this, and what can I do to get the same functionality?

class EnumEditActivity<E: Enum<E>>() {    
    var value: E? = null
    var allValues: Array<E> = E.values()
}

If I call values() on a normal enum, it works fine:

enum class Gender {
    male, female
}

for (value in Gender.values()) {
    println(value.name)
}

prints:

male
female

Some answers suggest doing something like this:

enum class SomeEnum {
    one, two
}

class EnumEditActivity<E: SomeEnum>() {    
    var value: E? = null
    val values = listCases<SomeEnum>()

    inline fun <reified E: SomeEnum> listCases() = (E::class.java).enumConstants.toList()
}

This doesn't work because it's not dynamic: it will always just get the cases for SomeEnum, so there's no point having a generic class. You can't pass any other enum apart from SomeEnum into the class, because one enum cannot inherit from another.

I don't think this is possible in Kotlin. I'm now just defining the class so it requires you to pass in an array of the enum's cases in the class initializer:

class EnumEditActivity<E>(val values: Array<E>)
like image 559
mef27 Avatar asked Aug 30 '19 18:08

mef27


People also ask

Can enums be generic?

However, it is possible to use enums in generics. The MSDN article for Enum gives the following type definition for the class Enum . This definition can be used to get enum s working as generic types by constraining the generic type to those of Enum .

Can enum have values?

Overview. The Java enum type provides a language-supported way to create and use constant values. By defining a finite set of values, the enum is more type safe than constant literal variables like String or int.

Can we give string value in enum?

Since C# doesn't support enum with string value, in this blog post, we'll look at alternatives and examples that you can use in code to make your life easier. The most popular string enum alternatives are: Use a public static readonly string. Custom Enumeration Class.

Can we change enum values in typescript?

An enum is usually selected specifically because it is immutable - i.e. you would never want the values to change as it would make your application unpredictable.


Video Answer


2 Answers

Because you have to call the function into the instance, not the type, to do so you have to reify the type variable:

interface  VisualEnum {
    fun get(fromName : String)
}

enum class VisuelEnumSub(lowerName: String) : VisualEnum {
    A("a"), B("b"), C("c");

    override fun get(name : String) {
        VisuelEnumSub.values().filter { it.toString().equals(name, true) }
    }}

open class AppCompatActivity{}

open class EnumEditActivity<E: VisualEnum>(): AppCompatActivity() {
    inline fun <reified A:E> onCreate() = (A::class.java).enumConstants
}

fun main(args: Array<String>) {
   EnumEditActivity<VisuelEnumSub>().onCreate<VisuelEnumSub>().forEach { println(it) }
}

result:

A
B
C
like image 141
A Monad is a Monoid Avatar answered Sep 28 '22 08:09

A Monad is a Monoid


You can only do this by passing the class as a parameter (because E is a class type parameter and reified isn't available):

class EnumEditActivity<E: Enum<E>>(cls: Class<E>) {    
    var value: E? = null
    var allValues: Array<E> = cls.enumConstants
}

inline fun <reified E: Enum<E>> EnumEditActivity() = EnumEditActivity(E::class.java)

// call as
EnumEditActivity<YourEnum>()

Or with your

class EnumEditActivity<E>(val values: Array<E>)

you can use the standard enumValues function:

inline fun <reified E: Enum<E>> EnumEditActivity() = EnumEditActivity(enumValues<E>())
like image 36
Alexey Romanov Avatar answered Sep 28 '22 06:09

Alexey Romanov