Search code examples
scalacollectionscomparison

Scala - Collection comparison - Why is Set(1) == ListSet(1)?


Why is the output of this comparison outputs true?

import scala.collection.immutable.ListSet

Set(1) == ListSet(1) // Expect false

//Output
res0: Boolean = true 

And in a more general sense, how the comparison is actually done?


Solution

  • Since the inheritance chain Set <: GenSet <: GenSetLike is a bit lengthy, it might be not immediately obvious where to look for the code of equals, so I thought maybe I quote it here:

    GenSetLike.scala:

      /** Compares this set with another object for equality.
       *
       *  '''Note:''' This operation contains an unchecked cast: if `that`
       *        is a set, it will assume with an unchecked cast
       *        that it has the same element type as this set.
       *        Any subsequent ClassCastException is treated as a `false` result.
       *  @param that the other object
       *  @return     `true` if `that` is a set which contains the same elements
       *              as this set.
       */
      override def equals(that: Any): Boolean = that match {
        case that: GenSet[_] =>
          (this eq that) ||
          (that canEqual this) &&
          (this.size == that.size) &&
          (try this subsetOf that.asInstanceOf[GenSet[A]]
           catch { case ex: ClassCastException => false })
        case _ =>
          false
      }
    

    Essentially, it checks whether the other object is also a GenSet, and if yes, it attempts to perform some fail-fast checks (like comparing size and invoking canEqual), and if the sizes are equal, it checks whether this set is a subset of another set, presumably by checking each element.

    So, the exact class used to represent the set at runtime is irrelevant, what matters is that the compared object is also a GenSet and has the same elements.