Kamil Kloch
Kamil Kloch

Reputation: 333

Scalatest implicit Equality for Containers

We define a customEquality[String]:

implicit val upperCaseEquality = new Equality[String] {
  override def areEqual(self: String, b: Any): Boolean = b match {
    case other: String => self.toUpperCase == other.toUpperCase
    case _ => false
  }
}

The following code works, as expected:

Seq("a").view should contain theSameElementsInOrderAs Seq("A")

Now, we add a custom Equality for Seq:

implicit def SeqEquality[T, SEQ[e] <: GenSeq[e]](implicit equality: Equality[T]): Equality[SEQ[T]] = new Equality[SEQ[T]] {
  override def areEqual(self: SEQ[T], b: Any): Boolean = b match {
    case other: GenSeq[_] => self.size == other.size && self.zip(other).forall(equality.areEqual _ tupled)
    case _ => false
    }
}

Custom TripleEquals equality works for Seq:

assert(Seq("a") === Seq("A"))

but does not work for SeqView:

assert(Seq("a").view === Seq("A"))

Exception in thread "main" org.scalatest.exceptions.TestFailedException: SeqView("a") did not equal List("A")

Why?

Upvotes: 2

Views: 718

Answers (1)

Owen
Owen

Reputation: 39366

If you look at what .view returns:

def view(from: Int, until: Int): SeqView[A, Seq[A]]

you see that SeqView[_, _] actually has two type parameters, so it is not conforming to your specification SEQ[e] <: GenSeq[e]. (In theory you could imagine that if Scala supported partially-applied type constructors this could be unified somehow, but it is a tricky problem and Scala does not support it).

In your case, you can make it work by making a definition that is explicit for SeqView and does not use higher-kinded types:

implicit def SeqViewEquality[T](implicit equality: Equality[T]): Equality[SeqView[T, Seq[T]]] = new Equality[SeqView[T, Seq[T]]] {
  override def areEqual(self: SeqView[T, Seq[T]], b: Any): Boolean = b match {
    case other: GenSeq[_] => self.size == other.size && self.zip(other).forall(equality.areEqual _ tupled)
    case _ => false
  }
}

Though, I admit this is somewhat unsatisfying.

Upvotes: 1

Related Questions