3

I have to use third-party traits which are designed as:

trait Super[T]
trait Sub[T] extends Super[T]

and I have defined the following method to provide instances for arbitrary sealed families:

implicit def subFor[T, Repr](
  implicit
  gen: LabelledGeneric.Aux[T, Repr],
  sg: Lazy[JsonFormat[Repr]]
): Sub[T] = ???

but somewhere else in the code, somebody has already defined

implicit def superFor[T]: Super[T] = ???

for some specific types, e.g. Option and a few others.

Actually, I'd like to use the existing implementations instead of using my subFor generic implementation. However, because my method returns Sub[T] and the existing implementation returns Super[T] I can't see any way to define my implementation in such a way that it is considered lower priority.

How can I block my subFor from being called for specific types? Is there some way to disable LabelledGeneric for specific types, or some priority reducing mechanism that would stop the compiler from ever looking for my subFor if it already sees a Super[T]?

Ben Reich
  • 16,222
  • 2
  • 38
  • 59
fommil
  • 5,757
  • 8
  • 41
  • 81

1 Answers1

2

If the implicit defs are defined in companion objects, you have to resort to collision-based type computations. But for "some specific types", the defs are usually not in companion objects of the class (e.g. not on object Option). In this case, you can take advantage of the fact that implicits hide each other within a given namespace. So you can just

implicit def superFor[T]: SomeThrowawayType = ???

and their superFor won't work any more. Since you change the return type, it won't collide or anything; it's effectively just gone. Then you can create your own forwarders at whatever priority level you want that explicitly call their defs.

This does require, however, that you import your stuff after theirs (so it shadows theirs). If this seems too fiddly to be relied upon, you'll have to go for the type computation.

Rex Kerr
  • 166,841
  • 26
  • 322
  • 407