2

I was recently introduced to the technique of prioritising implicits here:Link

Now, I am trying to generalise this to cases where the number of implicits > 2.

From this answer here, it says I can do this by creating a hierarchy of traits: Link

Here is some code where I would like to prioritise implicits:

object Example extends App {

  sealed trait Serializer[T] {
    def serialize(seq: List[T]): String
  }

  implicit object StringSerializer extends Serializer[String] {
    def serialize(seq: List[String]): String = seq.toString()
  }

  implicit object IntSerializer extends Serializer[Int] {
    def serialize(seq: List[Int]): String = seq.toString()
  }

  implicit object FloatSerializer extends Serializer[Float] {
    def serialize(seq: List[Float]): String = seq.toString()
  }

  case class Marker[T: Serializer](lst: Option[List[T]] = None)
  
  Marker() // ambiguous implicit values: here...
}

How could I impose the implicit priority of Float > Int > String in this case?

My attempt was as follows:

trait A {
    implicit object StringSerializer extends Serializer[String] {
      def serialize(seq: List[String]): String = seq.toString
    }
  }
  
  trait B extends A {
    implicit object IntSerializer extends Serializer[Int] {
      def serialize(seq: List[Int]): String = seq.toString
    }
  }

  trait C extends B {
    implicit object FloatSerializer extends Serializer[Float] {
      def serialize(seq: List[Float]): String = seq.toString
    }
  }

But this didn't work. Looking at the code I can see I am not doing it properly but I am unsure how to proceed.

Any guidance would be much appreciated.

1 Answers1

3

For example you can do

val c = new C {}
import c._

Marker() //compiles

or

object c extends C
import c._

Marker() //compiles

Or make C an object rather than trait

object C extends B {
  implicit object FloatSerializer extends Serializer[Float] {
    def serialize(seq: List[Float]): Value = ???
  }
}

import C._

Marker() //compiles

If you make C an object and rename it to Serializer (so C became the companion object of trait Serializer) then you'll not have to make the import

object Serializer extends B {
  implicit object FloatSerializer extends Serializer[Float] {
    def serialize(seq: List[Float]): Value = ???
  }
}

Marker() //compiles

Where does Scala look for implicits?

Where does Scala look for implicits?

Dmytro Mitin
  • 34,874
  • 2
  • 15
  • 47
  • 1
    Thanks @Dmytro, so a single object at the end of the trait chain can make the entire priority work - this is super useful! – finite_diffidence Jul 05 '20 at 15:10
  • 1
    @finite_diffidence Yes. For example in Cats here are objects extending traits https://github.com/typelevel/cats/blob/master/core/src/main/scala-2.13+/cats/instances/package.scala And you make imports like `import cats.instances.option._` – Dmytro Mitin Jul 05 '20 at 15:16