Reputation: 2411
Today I took a deep dive into Liskov's Substitution Principle and covariance/contravariance.
And I got stuck on the difference between:
T = TypeVar("T", bound=Union[A, B])
T = TypeVar("T", A, B, covariant=True)
My understanding of #1
Difference between TypeVar('T', A, B) and TypeVar('T', bound=Union[A, B])
This answer clearly states T
can be :
Union[A, B]
(or a union of any subtypes ofA
andB
such asUnion[A, BChild]
)A
(or any subtype ofA
)B
(or any subtype ofB
)
This makes perfect sense to me.
My flawed understanding of #2
Re-mentions the bound=Union[A, B]
case, but does not get at the meaning of option #2, A, B, covariant=True
.
I have tried playing around with mypy
, and can't seem to figure it out.
Can anyone point out what this means?
I think it means:
A
(or any subtype of A
)B
(or any subtype of B
)(aka it excludes the Union
case from above)
Here's sample code to show that they are actually different. The errors come from mypy==0.770
.
from typing import Union, TypeVar, Generic
class A: pass
class ASub(A): pass
class B: pass
# Case 1... Success: no issues found
# T = TypeVar("T", bound=Union[A, B])
# Case 2... error: Value of type variable "T" of "SomeGeneric" cannot be "ASub"
T = TypeVar("T", A, B, covariant=True)
class SomeGeneric(Generic[T]): pass
class SomeGenericASub(SomeGeneric[ASub]): pass
Upvotes: 59
Views: 30938
Reputation: 12503
Covariance and contra-variance are terms that relate to the intersection between object orientation and generics.
Here's the question this concept is trying to answer:
Base
and Derived
.List[T]
.Derived
can be used anywhere Base
can - does that mean that List[Derived]
can be used wherever List[Base]
can?List[Base]
can be used wherever List[Derived]
can?If the answer to (3) is yes, it's called covariance and we'll say declare List
as having covariance=True
. If the answer to (4) is true, it's called contra-variance. If none is true, it's invariant.
Bounds also come from the intersection of OO and generics. When we define a generic type MyType<T>
- does it mean that T
can be any type at all? Or, may I impose some limitations on what T
might be? Bounds allow me to state that the upper bound of T
is, for example, the class Derived
. In that case, Base
can't be used with MyType
- but Derived
and all its subclasses can.
The definition of covariance and contravariance can be found in this section of PEP-484.
Upvotes: 115