Ensuring uniqueness of enum constants

I want to ensure that a certain parameter value is not set twice in the set of enum constants. The best place would be a Set in the companion object to store used values, but the Set property of the companion object would be initialized after the enum constants!

So the best I’ve come up with is a Set outside of the enum in the same file:

private val ids = mutableSetOf<Int>()

enum class Thing(val id: Int) {

    RED(1),
    GREEN(2),
    BLUE(1);

    init {
        require(!ids.contains(id)) { "Duplicate id: $id" }
        ids.add(id)
    }
}

This throws:

Caused by: java.lang.IllegalArgumentException: Duplicate
	at Thing.<init>(Test.kt:16)
	at Thing.<clinit>(Test.kt:13)
	... 2 more

Any better ideas?

If this is something you only need once this is probably the best solution. If you need this on lot’s of enums you could write an annotation processor or compiler plugin to do this check at compile time.

1 Like

If what you want is only an integer, and you don’t care which enum entry is associated with which integer, then you can use ordinal property instead.

Example:

fun main() {

  for (u in Unique.values()) { print(u.ordinal)}

}
​
enum class Unique {
    FIRST,
    SECOND,
    THIRD
    
}

Otherwise, I don’t see any better solution.

My example was a bit simplistic, in fact there is more than one parameter.

Thank you both for your assessment. I will keep as is for now, since it is not worth to develop an annotation processor or compiler plug-in, but I like the idea.

You can write a test:

assertEquals(0, Thing.values()
        .groupBy { it -> it.id }
        .filter { it -> it.value.size > 1 }
        .size)
3 Likes

I second using a unit test in this case, as it avoids any runtime overhead. I do suggest using a library like AssertJ or assertk so that you write assertThat(Thing.values().groupBy { it.id }.filter { it.value.size > 1 }).isEmpty(), which will give you a useful error message of exactly which ids are used multiple times, and which enum values have each of those ids.

2 Likes