# Generic Types And Functions: Variance

Hack supports both generic covariance and contravariance on a type parameter.

Each generic parameter can optionally be marked separately with a variance indicator:

• `+` for covariance
• `-` for contravariance

If no variance is indicated, the parameter is invariant.

## Covariance

If `Foo<int>` is a subtype of `Foo<num>`, then `Foo` is covariant on `T`. 'co' means 'with'; and the subtype relationship of the generic type goes with the subtype relationship of arguments to a covariant type parameter. Here is an example:

``````<?hh

namespace Hack\UserDocumentation\Generics\Variance\Examples\Covariance;

// This class is readonly. Had we put in a setter for \$this->t, we could not
// use covariance. e.g., if we had function setMe(T \$x), you would get this
// cov.php:9:25,25: Illegal usage of a covariant type parameter (Typing)
//   cov.php:7:10,10: This is where the parameter was declared as covariant (+)
//   cov.php:9:25,25: Function parameters are contravariant
class C<+T> {
public function __construct(private T \$t) {}
}

class Animal {}
class Cat extends Animal {}

function f(C<Animal> \$p1): void { \var_dump(\$p1); }

function g(array<Animal> \$p1): void { \var_dump(\$p1); }

<<__EntryPoint>>
function run(): void {
f(new C(new Animal()));
f(new C(new Cat()));  // accepted

g(array(new Animal(), new Animal()));
g(array(new Cat(), new Cat(), new Animal())); // arrays are covariant
}
``````

A covariant type parameter is for read-only types. Thus, if the type can somehow be set, then you cannot use covariance.

Covariance cannot be used as the type of a parameter on any method, or as the type of any mutable property, in that class.

## Contravariance

If `Foo<num>` is a subtype of `Foo<int>`, then `Foo` is contravariant on `T`. 'contra' means 'against'; and the subtype relationship of the generic type goes against the subtype relationship of arguments to a contravariant type parameter. Here is an example:

``````<?hh

namespace Hack\UserDocumentation\Generics\Variance\Examples\Contravariance;

// This class is write only. Had we put in a getter for \$this->t, we could not
// use contravariance. e.g., if we had function getMe(T \$x): T, you would get
// con.php:10:28,28: Illegal usage of a contravariant type
//                   parameter (Typing)
//  con.php:5:10,10: This is where the parameter was declared as
//                   contravariant (-)
//  con.php:10:28,28: Function return types are covariant
class C<-T> {
public function __construct(private T \$t) {}
public function set_me(T \$val): void {
\$this->t = \$val;
}
}

class Animal {}
class Cat extends Animal {}

<<__EntryPoint>>
function main(): void {
\$animal = new Animal();
\$cat = new Cat();
\$c = new C(\$cat);
// calling set_me with Animal on an instance of C that was initialized with Cat
\$c->set_me(\$animal);
\var_dump(\$c);
}
``````

A contravariant type parameter is for write-only types. Thus, if the type can somehow be read, then you cannot use contravariant. (e.g., serialization functions are a good use case).

A contravariant type parameter cannot be used as the return type of any method in that class.