I am learning Scala in order to use it for a project.
One thing I want to get a deeper understanding of is the type system, as it is something I have never used before in my other projects.
Suppose I have set up the following code:
// priority implicits sealed trait Stringifier[T] { def stringify(lst: List[T]): String } trait Int_Stringifier { implicit object IntStringifier extends Stringifier[Int] { 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() } } import Double_Stringifier._ object Example extends App { trait Animal[T0] { def incrementAge(): Animal[T0] } case class Food[T0: Stringifier]() { def getCalories = 100 } case class Dog[T0: Stringifier] (age: Int = 0, food: Food[T0] = Food()) extends Animal[String] { def incrementAge(): Dog[T0] = this.copy(age = age + 1) } } So in the example, there is a type error:
ambiguous implicit values: [error] both object DoubleStringifier in object Double_Stringifier of type Double_Stringifier.DoubleStringifier.type [error] and value evidence$2 of type Stringifier[T0] [error] match expected type Stringifier[T0] [error] (age: Int = 0, food: Food[T0] = Food()) extends Animal[String] Ok fair enough. But if I remove the context bound, this code compiles. I.e. if I change the code for '''Dog''' to:
case class Dog[T0] (age: Int = 0, food: Food[T0] = Food()) extends Animal[String] { def incrementAge(): Dog[T0] = this.copy(age = age + 1) } Now I assumed that this would also not compile, because this type is more generic, so more ambiguous, but it does.
What is going on here? I understand that when I put the context bound, the compiler doesn't know whether it is a double or an int. But why then would an even more generic type compile? Surely if there is no context bound, I could potentially have a Dog[String] etc, which should also confuse the compiler.
From this answer: "A context bound describes an implicit value, instead of view bound's implicit conversion. It is used to declare that for some type A, there is an implicit value of type B[A] available"