Search code examples
enumskotlincircular-reference

Circular reference in Kotlin Enum


How can I create an enum class with circular references?

Simple example (taken from this Java question):

enum class Hand(val beats: Hand) {
    ROCK(SCISSORS), // Enum entry 'SCISSORS' is uninitialized here
    PAPER(ROCK),
    SCISSORS(PAPER);
}

Solution

  • As reassignment is forbidden for val properties, this problem is generally hard to solve and often indicates problems in your data model. For a discussion in broader context refer to this question/answer(s).

    However, this simple example can be solved using a val property with custom getter (thus without a backing field). Using when, the getter can be defined in a very readable way:

    enum class Hand {
        ROCK,
        PAPER,
        SCISSORS;
    
        val beats: Hand
            get() = when (this) {
                ROCK -> SCISSORS
                PAPER -> ROCK
                SCISSORS -> PAPER
            }
    }
    

    An alternative solution (analogue to the answer by Eugen Pechanec) is to use sealed classes. Due to their less constrained concept, the implementation is1 slightly simpler and more readable compared to an enum with overridden properties.

    sealed class Hand {
        abstract val beats: Hand
    
        object ROCK: Hand() {
            override val beats = SCISSORS
        }
    
        object PAPER: Hand() {
            override val beats = ROCK
        }
    
        object SCISSORS: Hand() {
            override val beats = PAPER
        }
    }
    

    1personal opinion

    Disclaimer: I have no information on how these solutions work in conjunction with classic Java.