Dmitrii Bundin Dmitrii Bundin - 21 days ago 9
Scala Question

How to compare that two Traversables contain exactly the same elements?

I want to check if two

Traversable
s contain the same elements without respect to their order.

So, I tried it myself and wrote the following simple example:

implicit val l = 3
implicit def equality(implicit l: Int) = new Equality[String] {
override def areEqual(a: String, b: Any): Boolean = (a, b) match {
case (_, b: Int) => a.toInt == b
}
}

"Test" should "check how equality works" in {
List("1") should contain theSameElementsAs Vector(1) //Fine
List("1", "2") should contain theSameElementsAs Vector(1, 2) //Fine
List("1", "2", "3") should contain theSameElementsAs Vector(1, 2, 3) //Fine
List("1", "2", "2") should contain theSameElementsAs Vector(1, 2, 2) //Error
List("2", "1") should contain theSameElementsAs Vector(1, 2) //Error
}


As the the documentation says:


The "
contain theSameElementsAs
" syntax lets you assert that two
aggregations contain the same objects


It shouldn't take duplication and order into account. What's wrong with that?

Answer

I think that the fundamental issue is that the equality relation is not reflective, as one would expect. That is if x == y then y == x.

Scalacheck tries to count the number of repetitions in target collection using the equality function provided.

When it meets equality(2,2), tryEquality fails internally with a ClassCastException, defaulting the comparison to false.

Bottom line: Equality needs to be reflective (as good old math dictates) in order to have the expected result.