When declaring a case object, make it
final.
While case objects are effectively final in Scala - you can’t extend them - they are not always flagged as such in the compiled bytecode.
Take the following code, for example:
class Test {
case object foo
}
When foo is not flagged as final, running the class file through javap -c yields the following (truncated) output:
public class Test$foo$ implements scala.Product,scala.Serializable {
// [...]
When it’s flagged as final, however, we get:
public final class Test$foo$ implements scala.Product,scala.Serializable {
// [...]
To make matters worse, this is not even coherent accross Scala versions - the previous output was obtained with 2.12.7, but 2.11.8, for example, will compile both versions of Test.foo as final.
This might not seem like a big deal - as far as scalac is concerned, Test.foo is final either way and you won’t be able to extend it - not having this information in the bytecode will:
final-specific optimisationsjavac will let you extend Test.foo.