I write the following code:
class Animal
class Bird extends Animal
val animalList = List(new Animal, new Animal)
new Bird :: animalList
The implementation of the ::
method looks like this:
def ::[B >: A] (x: B): List[B] =
new scala.collection.immutable.::(x, this)
I expected the return type to be List[Bird]
. Why is it List[Animal]
?
The dotless infix notation of
new Bird :: animalList
desugars to
animalList.::(new Bird)
because method names ending with :
are invoked on the object on the right-hand side of the expression.
If we explicitly specify Bird
as the type argument...
animalList.::[Bird](new Bird)
... then the compiler tells us why that doesn't work:
error: type arguments
[Bird]
do not conform to method::
's type parameter bounds[B >: Animal]
There are two constraints on the type of B
:
B >: A
in the method signature means B
has to be a supertype of the list's type (A
, which here is Animal
).new Bird
) has to be an instance of B
(because method arguments are covariant).The compiler chooses the most specific type that satisfies both of these constraints, which is Animal
.
animalList.::[Animal](new Bird)