Skip to content

Instantly share code, notes, and snippets.

@eggm0n
Created November 30, 2017 09:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save eggm0n/72d154f93a23b7184ff54c4eda441578 to your computer and use it in GitHub Desktop.
Save eggm0n/72d154f93a23b7184ff54c4eda441578 to your computer and use it in GitHub Desktop.
covariance and contravariance
class GParent
class Parent extends GParent
class Child extends Parent
class Box[+A]
class Box2[-A]
def foo(x : Box[Parent]) : Box[Parent] = identity(x)
def bar(x : Box2[Parent]) : Box2[Parent] = identity(x)
foo(new Box[Child]) // success
foo(new Box[GParent]) // type error
bar(new Box2[Child]) // type error
bar(new Box2[GParent]) // success
When we declare List[A+], we are saying that List is covariant in the parameter A.
What that means is that it takes a type, say Parent, to a new type List[Parent], and if Child is a subtype of Parent, then List[Child] will be a subtype of List[Parent].
If we’d declared List to be contravariant (List[-A]), then List[Child] would be a supertype of List[Parent].
There’s one final possibility. Since subtyping is a partial order, we can have two types where neither one is a subtype of the other.
There’s no reason in principle why a type constructor T couldn’t take Parent and Child to new types which were completely unrelated.
In Scala, this is the case when you don’t provide an annotation for the type in the declaration; such a constructor is said to be invariant in that parameter. Arrays, for example, have this property.
https://www.atlassian.com/blog/software-teams/covariance-and-contravariance-in-scala
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment