Question

I would like the following code to compile, after making forgetBA implicit again.

trait ImplicitExample {
  trait AA[T]
  trait AB[T] extends AA[T]
  trait BA[T] extends AA[T]
  trait BB[T] extends AB[T] with BA[T]

  object AA {
    implicit def forgetAB[T: AB]: AA[T] = implicitly[AA[T]]
    /*implicit*/ def forgetBA[T: BA]: AA[T] = implicitly[AA[T]]
  }

  object AB {
    implicit def forgetBB[T: BB]: AB[T] = implicitly[AB[T]]
  }
  object BA {
    implicit def forgetBB[T: BB]: BA[T] = implicitly[BA[T]]
  }
  object BB {
    implicit object BBInt extends BB[Int]
  }

  val AAInt = implicitly[AA[Int]]
}

I understand that this will result in an ambiguous implicit resolution problem, so I'm looking for a way to indicate a preference for one implicit resolution over the other.

I've heard rumours that inserting intermediate traits in some way might help, but I can't seem to find an explanation.

Was it helpful?

Solution

The usual trick is to write something like this:

trait LowPriorityAAInstances {
  implicit def forgetAB[T: AB]: AA[T] = implicitly[AA[T]]
}

object AA extends LowPriorityAAInstances {
  implicit def forgetBA[T: BA]: AA[T] = implicitly[AA[T]]
}

This will give forgetBA priority when looking for an instance of AA for a T for which there's an instance of BA (while still compiling even if there's an instance of AB around).

The naming is entirely a matter of convention, but it's a good idea to use it to indicate that you're only breaking up the definition of AA in this way to accommodate the implicit search mechanism.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top