Description
I (Guido) wondered how I would compare two arguments whose type is a type variable:
def cmp(a: T, b: T) -> int:
if a < b: return -1
if a > b: return 1
return 0
Jukka wrote:
"""
This is a long-standing issue, and we've discussed this before in some detail (e.g., https://github.com/JukkaL/typing/issues/9). However, it wasn't discussed in typehinting, as far as I can tell. Currently we need to use a cast to use < instead of ==, which is pretty ugly.
We could define a Comparable ABC and support that as an "upper bound" for a type variable (bounded polymorphism). About the simplest useful implementation would be like this:
class Comparable(metaclass=ABCMeta):
@abstractmethod
def __gt__(self, other: Any) -> bool: pass
... # __lt__ etc. as well
...
CT = TypeVar('CT', bound=Comparable) # This is different from TypeVar('CT', Comparable)!
def min(x: CT, y: CT) -> CT:
if x < y:
return x
else:
return y
f(1, 2) # ok, return type int
f('x', 'y') # ok, return type str
f('x', 1) # probably ok, return type Comparable, which is not optimal
f(int, int) # error, types aren't comparable
However, this doesn't verify whether the types can be compared to each other, only that they can be compared to something (because of the Any argument type). This feature would be easy to add to mypy.
The way Java etc. do this is to support a fancier language feature called "F-bounded polymorphism" or "F-bounded quantification". With it we can say that int can be compared with only int (Comparable[int]), etc. For example:
class Comparable(Generic[T]):
@abstractmethod
def __gt__(self, other: T) -> bool: pass
... # __lt__ etc. as well
...
CT = TypeVar('CT', bound=Comparable['CT']) # Any type that is comparable with itself
def min(x: CT, y: CT) -> CT:
if x < y:
return x
else:
return y
f(1, 2) # ok, return type int
f('x', 'y') # ok, return type str
f('x', 1) # error, since these are not comparable to each other
f(int, int) # error, types aren't comparable at all
This would be more involved to add to mypy. It would probably be one or two days of work for a minimal implementation. I'm not even quite sure that the above would be sufficiently general (Comparable should be contravariant, I think, so that Comparable[object] is a subtype of Comparable[int] :-/ ).
Comparable is probably the only common use case for this complex feature.
"""