Enum cases change hashcodes between runs

I found that enum cases change hashcodes between runs unlike case objects that keep the same hashcodes.

enum Foo:
  case Bar, Baz

case object Bar2
println(Foo.Bar.hashCode()) //changes value each run
println(Bar2.hashCode()) //stable value each run

I didn’t see this behavior documented anywhere and is quite unexpected.
Is this an expected change derived from how enums are built or a bug?

Workaround:

trait StableEnum extends scala.reflect.Enum:
  override def hashCode: Int =
    if (this.getClass.isAnonymousClass())
      // uses both the enum class name and
      // the case enum to get a unique and stable hash
      (this.getClass.getName, this.ordinal).hashCode()
    else
      (this.getClass.getName, this.productIterator.toList).hashCode()

enum Foo extends StableEnum:
  case Bar, Baz
  case Gogo(arg: Int)

println(Foo.Bar.hashCode)
println(Foo.Gogo(1).hashCode)
println(Foo.Gogo(2).hashCode)
1 Like

Distantly related ticket about tableswitch

where ordinal changes if someone adds an element or reorders.

I remember the old Java advice not to rely on it directly.

1 Like