Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dis-ambiguating implicit resolution in Scala

Tags:

scala

implicit

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.

like image 601
Scott Morrison Avatar asked Dec 03 '25 05:12

Scott Morrison


1 Answers

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.

like image 92
Travis Brown Avatar answered Dec 05 '25 22:12

Travis Brown