Equals is not working correctly for two logically equals instance of case class. Please find below simplified case classes :-
case class Item(name : String)
case class Basket(items : Array[Item], bills : Map[Int, Int])
def createBasketInstance() : Basket = {
val maggi = Item("milk")
val coffee = Item("coffee")
val bills1 = Map(1 -> 20, 2 -> 75)
Basket( Array(maggi, coffee), bills1 )
}
val basket1 = createBasketInstance()
val basket2 = createBasketInstance()
Expected Result for basket1.equals(basket2) is true, but it actually prints false.
scalafiddle link : https://scalafiddle.io/sf/iJRKnMk/0
Please find attached screenshot also to confirm equals comparison using scalatest.
This has nothing to do with the default equals
of the case classes
but that of the Arrays
(this is one of the millions reasons you should use Lists
over Arrays
btw)
In Scala Arrays are just plain Java arrays and arrays in Java are treated specially (because JVM)
Even a simple
Array(1, 2, 3) == Array(1, 2, 3)
will return false.
Why? Because Object.equals
which the Arrays inherit the equals
method from only compared the array references and NOT their content.
I know this doesn't sound as bad as it is, but believe it gets worse.
You might think simply assigning your array to a value would fix it right? Well it doesn't. The following will fail as well...
def createBasketInstance() : Basket = {
val maggi = Item("milk")
val coffee = Item("coffee")
val arr = Array(maggi, coffee)
val bills1 = Map(1 -> 20, 2 -> 75)
Basket( arr, bills1 )
}
Because the call stacks of the different invocation of this function is not able to share references and thus each function call fill create a new reference even though the underlying content is the same.
How do you solve this?
There is a method in java.utils.Arrays
called Arrays.equals
that will do a deep comparison. You can override
it and construct it such that the comparison uses Arrays.equals
. You might also need to override hashCode
Write an implicit conversion from Array
to literally any other collection
Don't use Arrays in the first place.
I would say #3 is the way to go about this