Consider the following simple implementation of a stack in Scala:
abstract class Stack[+A] {
def top: A
def pop: Stack[A]
}
case object EmptyStack exten
def push[B >: A](x: B): Stack[B] = ...
...
Why is this allowed? Doesn't the type bound
>:
mean that only supertypes should be allowed?
Only super-types are allowed as B
, in your example Apple
. But x: B
is in a contravariant (input) position, and as such you can always pass a more specific value as an argument. That has nothing to do with the definition of B
. What you will see however is that the inferred type for honeycrisp
is Apple
not Honeycrisp.
This is indeed perplexing, and I remember having wondered about this once. But if you go through the implications, it really preserves the type soundness. Of course as a consequence, from the point of view of the body of push
, x
is really Any
without specific capabilities it could count on.
Possibly related: