Circular reference in Kotlin Enum

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.


An alternative to mhoff's answer without flow control statements:

enum class Hand {
    ROCK {
        override val beats: Hand
            get() = SCISSORS
    },
    PAPER {
        override val beats: Hand
            get() = ROCK
    },
    SCISSORS {
        override val beats: Hand
            get() = PAPER
    };

    abstract val beats: Hand
}