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 ofA
)B
(or any subtype ofB
)
(aka it excludes the Union
case from above)
**Edit**
It was asked in the comments:
Are you sure that they're actually different?
Here's sample code to show the difference. 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
**Edit 2**
I ended up asking about this in python/mypy #8806: Generic[T_co] erroring when T_co = TypeVar("T_co", A, B, covariant=True) and passed subclass of A
This cleared up some misunderstandings I had. Turns out TypeVar("T", A, B, covariant=True)
isn't really correct, knowing the value restrictions A
and B
aren't actually covariant.
Use of covariant=True
syntax is only helpful when they're related.