If you try to compile this code, you will get a type mismatch error from the compiler, and it should also tell you
Note: Some <: Option, but trait Functor is invariant in type F.
You may wish to define F as +F instead. (SLS 4.5)
Your Functor
trait being invariant in F
means, that a Functor[A]
and a Functor[B]
do not have any subtyping relation, regardless of any subtype relation between A
and B
.
The compiler suggests the fix of defining F
as +F
, which means making Functor
covariant in F
, so Functor[A]
is a subtype of Functor[B]
if A
is a subtype of B
:
trait Functor[+F[_]] {
def map[A, B](fa: F[A])(f: A => B): F[B]
}
But this will also cause a compile error:
covariant type F occurs in contravariant position in type F[A] of value fa
The reason is, that a covariant type may only be used in a covariant position, i.e as a return type (usually), but not as a parameter to a method (a contravariant position).
This rule is necessary, because you could have invalid code otherwise. A valid implementation for Functor[Some]
could look like this:
new Functor[Some] {
def map[A,B](fa: Some[A])(f: A=>B): Some[B] = Some(f(fa.value))
}
If you could assign this to a Functor[Option]
value, the method on it would allow passing Option
s, which do not have the value
field (they may be None
after all).
Regarding your example with Seq
and List
, you can see that Seq[+A]
is covariant in its type parameter. You may wonder how this is possible, as the documentation contains methods like this:
def +:(elem: A): Seq[A]
But the documentation is actually cheating here to make the signature look simpler. If you look at the source code, the real signature is
def +: [B >: A](elem: B): CC[B]
so it takes any B
, which is a supertype of A
, and creates a collection of type B
.
You will also note, that Seq
does not contain any methods that mutate the collection. All mutable collections in the standard library are invariant in their element type, as their methods for adding need to take elements of the generic type.
More on variance can be found in the Scala Tour.