Given:
class Invar[T]
trait ExtendsAnyref extends AnyRef
def f(a: Invar[ExtendsAnyref]) = {}
The following is erroneous
scala> val x: Function1[Invar[_ <: AnyRef], Unit] = f
<console>:13: error: type mismatch;
found : Invar[ExtendsAnyref] => Unit
required: Invar[_ <: AnyRef] => Unit
val x: Function1[Invar[_ <: AnyRef], Unit] = f
^
Why?
I understand that in Scala, generic types have by
default nonvariant subtyping. Thus, in the context of this example, instances of Invar
with different type parameters would never be in a subtype relationship with each other. So an Invar[ExtendsAnyref]
would not be usable as a Invar[AnyRef]
.
But I am confused about the meaning of _ <: AnyRef
which I understood to mean "some type below AnyRef
in the type hierarchy." ExtendsAnyref
is some type below AnyRef
in the type hierarchy, so I would expect Invar[ExtendsAnyref]
to conform to Invar[_ <: AnyRef]
.
I understand that function objects are contravariant in their input-parameter types, but since I use Invar[_ <: AnyRef]
rather than Invar[AnyRef]
I understood, apparently incorrectly, the use of the upper bounds would have the meaning "Invar
parameterized with Anyref
or any extension thereof."
What am I missing?
When you write
val x: Function1[Invar[_ <: AnyRef], Unit] = ...
it means x
must accept any Invar[_ <: AnyRef]
. That is, it must accept Invar[AnyRef]
, Invar[String]
, etc. f
obviously doesn't: it only accepts Invar[ExtendsAnyref]
.
In other words, you need to combine your last two paragraphs: because functions are contravariant in argument types, for Function1[Invar[ExtendsAnyref], Unit]
to conform to Function1[Invar[_ <: AnyRef], Unit]
you'd need Invar[_ <: AnyRef]
to conform to Invar[ExtendsAnyref]
, not vice versa.
If you
want a function that takes Invar parameterized with any subclass of AnyRef
this can be written as Function1[Invar[A], Unit] forSome { type A <: AnyRef }
. However, I don't believe there is anything useful you could do with an object of this type, because 1) the only thing you can do with a function is to apply it to an argument, but 2) you don't know what arguments this function accepts.