Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should I use the final modifier when declaring case classes?

According to scala-wartremover static analysis tool I have to put "final" in front of every case classes I create: error message says "case classes must be final".

According to scapegoat (another static analysis tool for Scala) instead I shouldn't (error message: "Redundant final modifier on case class")

Who is right, and why?

like image 718
sscarduzio Avatar asked Jan 02 '16 01:01

sscarduzio


People also ask

For which kind of data should you use a case class?

Case classes are good for modeling immutable data. In the next step of the tour, we'll see how they are useful in pattern matching.

Can case class be Extends case class?

Case Class can NOT extend another Case class. However, they have removed this feature in recent Scala Versions. So a Case Class cannot extend another Case class.

What is final class in Scala?

In Scala, Final is a keyword and used to impose restriction on super class or parent class through various ways. We can use final keyword along with variables, methods and classes.


1 Answers

It is not redundant in the sense that using it does change things. As one would expect, you cannot extend a final case class, but you can extend a non-final one. Why does wartremover suggest that case classes should be final? Well, because extending them isn't really a very good idea. Consider this:

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 // ???? 

Really? Bar(1,1) equals Bar(1,2)? This is unexpected. But wait, there is more:

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) // ??? 

A copy of Bar has type Foo? Can this be right?

Surely, we can fix this by overriding the .equals (and .hashCode, and .toString, and .unapply, and .copy, and also, possibly, .productIterator, .productArity, .productElement etc.) method on Bar and Baz. But "out of the box", any class that extends a case class would be broken.

This is the reason, you can no longer extend a case class by another case class, it has been forbidden since, I think scala 2.11. Extending a case class by a non-case class is still allowed, but, at least, in wartremover's opinion isn't really a good idea.

like image 126
Dima Avatar answered Sep 18 '22 12:09

Dima