Search code examples
scalagenericsimplicit-conversioncontext-bound

Type Error for Context Bounding with Priority Implicits


I have the following issue, and I am confused as to what is going:

  1. I have a priority implicit defined
  2. I use this priority implicit to impose a context bound
  3. I declare a case class with a default field, which has values that are covered by the context bound
  4. I am still getting a type error

A minimal working example which reflects the actual code I am working on. I basically need the priority implicits in other part of my code:

    // priority implicits
    sealed trait Stringifier[T] {
      def stringify(lst: List[T]): String
    }
    
    trait Int_Stringifier {
      implicit object IntStringifier {
        def stringify(lst: List[Int]): String = lst.toString()
      }
    }
    
    object Double_Stringifier extends Int_Stringifier {
      implicit object DoubleStringifier extends Stringifier[Double] {
        def stringify(lst: List[Double]): String = lst.toString()
      }
    }
    
    object Example extends App {
    
      trait Animal[T0] {
        def incrementAge(): Animal[T0]
      }
    
      case class Dog[T0: Stringifier]
      (age: Int = 0, locations: List[T0] = List(1, 2, 3)) extends Animal[String] {
        def incrementAge(): Dog[T0] = this.copy(age = age + 1)
      }
    }
 val t = Dog(age = 100)

I get a type mismatch error:

required List[T0]

found List[Int]

What is going on here? I reasoned that since I am creating my default parameters within the bound, the type should match. Am I missing some trick here to make this work?


Solution

  • It's not clear how to reproduce your compile error

    required List[T0]
    
    found List[Int]
    

    The code you added

    val t = Dog(age = 100)
    

    produces a different error

    Error: could not find implicit value for evidence parameter of type App.Stringifier[Int]
    Error occurred in an application involving default arguments.
        val t = Dog(age = 100)
    

    This is because you missed extends Stringifier[Int] and import Double_Stringifier._

    trait Int_Stringifier {
      implicit object IntStringifier extends Stringifier[Int] {
        def stringify(lst: List[Int]): String = lst.toString()
      }
    }
    
    import Double_Stringifier._
    
    val t = Dog(age = 100) // compiles