Selon scala-wartremover outil d'analyse statique, je dois mettre "final" devant chaque classe de cas que je crée: le message d'erreur dit "les classes de cas doivent être finales".
Selon bouc émissaire (un autre outil d'analyse statique pour Scala), je ne devrais pas (message d'erreur: "Modificateur final redondant sur la classe de cas")
Qui a raison et pourquoi?
Ce n'est pas redondant dans le sens où son utilisation change les choses. Comme on peut s'y attendre, vous ne pouvez pas étendre une classe de cas finale, mais vous pouvez étendre une classe non finale. Pourquoi wartremover suggère-t-il que les classes de cas soient finales? Eh bien, parce que les étendre n'est pas vraiment une très bonne idée. Considère ceci:
scala> case class Foo(v:Int)
defined class Foo
scala> class Bar(v: Int, val x: Int) extends Foo(v)
defined class Bar
scala> new Bar(1, 1) == new Bar(1, 1)
res25: Boolean = true
scala> new Bar(1, 1) == new Bar(1, 2)
res26: Boolean = true
// ????
Vraiment? Bar(1,1)
est égal à Bar(1,2)
? C'est inattendu. Mais attendez, il y a plus:
scala> new Bar(1,1) == Foo(1)
res27: Boolean = true
scala> class Baz(v: Int) extends Foo(v)
defined class Baz
scala> new Baz(1) == new Bar(1,1)
res29: Boolean = true //???
scala> println (new Bar(1,1))
Foo(1) // ???
scala> new Bar(1,2).copy()
res49: Foo = Foo(1) // ???
Une copie de Bar
a le type Foo
? Cela peut-il être vrai?
Certes, nous pouvons résoudre ce problème en remplaçant le .equals
(Et .hashCode
, Et .toString
, Et .unapply
, Et .copy
, Et aussi , éventuellement, .productIterator
, .productArity
, .productElement
etc.) méthode sur Bar
et Baz
. Mais "prêt à l'emploi", toute classe qui étend une classe case serait rompue.
C'est la raison pour laquelle vous ne pouvez plus étendre une classe de cas par une autre classe de cas, cela a été interdit depuis, je pense scala 2.11. L'extension d'une classe de cas par une classe non-cas est toujours autorisé, mais, au moins, de l'avis de wartremover n'est pas vraiment une bonne idée.