vda
August 4, 2024, 2:19am
1
import cats._
import cats.implicits._
@main
def mainEq(): Unit = {
case class Car(model: String, year: Int)
given given_eqCar: Eq[Car] with
override def eqv(x: Car, y: Car): Boolean = x.year == y.year
val otherEqCar: Eq[Car] = Eq.instance[Car]((car1, car2) => car1.model == car2.model)
given given_otherEqCar: Eq[Car] = otherEqCar
println(Car("Ford", 2000) === Car("Mazda", 2000))
//true
}
so why first given is used?)
I have some notes with more details here: scala-functional-programming-tutorial/scala-intro/src/main/scala/co/edu/eafit/dis/progfun/scala/intro/ImplicitsNotes.scala at master · BalmungSan/scala-functional-programming-tutorial · GitHub
But, the TL;DR; is that the compiler picks the “most specific” implicit, and here the word “specific” means down in the inheritance chain.
And the with
syntax creates an anonymous instance that has its own type, compared with an alias that is just a val
with the given type. Thus given_eqCar
ends up having a more specific type.
Someone else may explain this using correct terminology. But, hopefully, this quick reply of mine is enough to give you a vague understanding of what is happening.
2 Likes
Note that this priority will be reversed soon.
3 Likes
Why is it necessary that Eq
extend Any
?
The givens are ambiguous otherwise (for both old 3.4.2 and new 3.6 resolution).
Why are they ambiguous in that case?
import scala.language.implicitConversions
case class K(i: Int, s: String)
@main def test = println:
given x: Eq[K] with
def eqv(x: K, y: K): Boolean = x.i == y.i
override def toString = "C"
given c: Eq[K] = new Eq[K] {
def eqv(x: K, y: K): Boolean = x.s == y.s
}
println:
summon[Eq[K]]
import ksyntax.*
K(42, "hi") === K(42, "bi")
end test
object ksyntax extends EqSyntax
trait Eq[A] extends Any:
//trait Eq[A]:
def eqv(x: A, y: A): Boolean
trait EqSyntax:
implicit def catsSyntaxEq[A: Eq](a: A): EqOps[A] = new EqOps[A](a)
final class EqOps[A: Eq](lhs: A):
def ===(rhs: A): Boolean = summon[Eq[A]].eqv(lhs, rhs)
1 Like