Samar Samar - 2 months ago 15
Scala Question

subtyping and type coercion

The type

T
below is a subtype of
Fruit
.
Apple
is also a subtype of
Fruit
. So, why doesn't the compiler coerce Apple to T when a type ascription is used below. Why do we need an explicit casting to make it work? What are the rules for coercion when inferring types?

trait Fruit
case class Apple(id: String) extends Fruit

type T <: Fruit

val t: T = Apple("apple") // why doesn't the compiler coerce Apple to T?

val t: T = Apple("apple").asInstanceOf[T] // works!

Answer

Let's simplify this a bit. Replce T with Pear and Fruit with Fetus.

 trait Fetus
 class Apple extends Fetus
 type Pear <: Fetus

 val t: Pear = new Apple()

We declared Fetus, then we said "Apple is Fetus" and then "Pear is Fetus". Our logic is correct so far. But then we try to "put the apple into the box for pears". And here is our mistake.

Let's consider another example:

trait Fetus
class Apple extends Fetus
type Fruit >: Apple <: Fetus

val t: Fruit = new Apple()

Here we declared Fetus, then we said "Apple is Fetus" and then we said that "Fruit is something in the middle between Apple and Fetus". In another words we built following hierarchy: Fetus -> Fruit -> Apple. So, now Apple is subtype of Fruit and you can "put apples into the box for fruit".

UPDATE:

A Pear definitely cannot be and Apple, like a Cat cannot be a Dog in spite of they both are animals. You can go by hierarchy only vertically but not horizontally:

Creature
   |
Animal
  _|_
 /    \
Dog    Cat
        \
       White Cat