Two given in scope

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