scalacovariant

How to interpret :: in scala


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]?


Solution

  • 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:

    The compiler chooses the most specific type that satisfies both of these constraints, which is Animal.

    animalList.::[Animal](new Bird)