Search code examples
kotlinclassenumsdeclaration

In Kotlin, how to declare a class with Enum property?


I'm creating a Kotlin structure that I intend to reuse in several Android games with a similar format: a single grid with multiple cells. Depending on the game, the cells will have a different set of possible states. The set of states will be an Enum, but the contents will vary from game to game.

So I want a structure like:

class Cell(state: Enum) {
    ...
}

where the state parameter will be something different for each game.

For instance,

enum class TicTacToeState{
    BLANK, X, O
}

val cell = Cell(TicTacToeState.BLANK)

or

enum class SeaBattleState{
    BLANK, END, SUB, WATER
}

val cell = Cell(SeaBattleState.SUB)

The problem is when I type the structure at the top, Android Studio tells me, "One type argument expected for class Enum<E : Enum>".

I can't imagine what type I should call the Enum since I don't know what the contents will be, nor what type "BLANK" even is in the the context of an ENUM value. I've searched Google and here, but can't find any pages that deal in the class name Enum with a type declaration, as opposed to the lowercase enum to declare a class as an Enum.

So my question is, how do I declare a Kotlin class with a parameter of type Enum when I don't know yet what any of the Enums will be?


Solution

  • First of all, you need to be aware Enum type is a little confusing at first in Java/Kotlin, because it is parameterized against itself. This adds some complexity to a case which we expect to be simple.

    If we don't care what's the exact type of the enum, we could use Enum<*>:

    class Cell(val state: Enum<*>)
    

    This is a direct equivalent of your code.

    However, this is not very useful. If we have a Cell, we can get its enum value, we can check ordinal and name of the enum, but we don't know what is this enum type exactly, we can't switch/when on it easily, etc.:

    val s = when (cell.state) {
        TicTacToeState.BLANK -> ""
        TicTacToeState.X -> "X"
        TicTacToeState.O -> "O"
    }
    

    In the above case, IntelliJ won't help us find possible values for the state. Also, above code doesn't compile, because the compiler doesn't understand the when is exhaustive. We would have to cast to TicTacToeState manually.

    In order to know the enum type, we have to make the Cell generic. However, this is a little more complicated than usual, because of what was said at the beginning. We have to create a type parameter which is an enum targeting the same type. It's easier to do than explain:

    class Cell<T : Enum<T>>(val state: T)
    

    With this code, we don't just get a Cell, we have Cell<TicTacToeState> and the type of the enum is known to the compiler.