In Scala 2 the == operator is used for checking by value equality, in contrast with Java where .equals() is best practice. Also in contrast to Java, == is safe to be used on null values.
This is because == forwards to .equals(), but right before it a null-check is performed.
We can see this on AnyRefs.equals() scaladoc:
x == thatis equivalent to
if (x eq null) that eq null else x.equals(that).
Here we see the .eq() which tests equality by reference, which is very rarely needed, specially in FP.
This makes usage of .equals() a bad practice in Scala since it can throw exception when the left part is null. Always use == instead of equals() in Scala.
== for collections means:
- they are of the same collection type (Seq vs Set vs Map)
- they contain the same elements (as defined by the == on the element type)
- for sequences elements are in the same order
Imperfections of ==
1. Doesn’t work on Arrays
Never use == on arrays, they do not behave like collections when comparing! I still get burned by this and it’s what motivated this post.
The solution here is to use Array.sameElements
But we humans always make errors so best to block usage of == with Wartremover:
//in plugins.sbt addSbtPlugin("org.wartremover" % "sbt-wartremover" % "2.4.13") //in build.sbt wartremoverErrors += Wart.ArrayEquals
This will throw compilation errors when comparing arrays with ==
[error] [wartremover:ArrayEquals] == is disabled, use sameElements instead [error] println(Array(1, 2, 3) == Array(1, 2, 3))
2. Allows comparing different types
Because == is defined on AnyRef it can compare any two refs, regardless the type. This is a scenario that will always evaluate to false, it is very error prone so the compiler should not even let us write this.
Cats defines triple equals, which does not allow comparing different types.
This won’t work out of the box for arrays. We have to provide an Eq instance for them:
Having all this we can go ahead and block usage of == altogether
//in build.sbt wartremoverErrors ++= Seq(Wart.Equals, Wart.ArrayEquals)