[Python-ideas] Type Hinting Kick-off
Eugene Toder
eltoder at gmail.com
Thu Dec 25 01:50:09 CET 2014
More information about the Python-ideas mailing list
Thu Dec 25 01:50:09 CET 2014
- Previous message: [Python-ideas] Type Hinting Kick-off
- Next message: [Python-ideas] Type Hinting Kick-off
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Guido van Rossum <guido at ...> writes: > A few months ago we had a long discussion about type hinting. I've thought a > lot more about this. I've written up what I think is a decent "theory" > document -- writing it down like this certainly helped *me* get a lot of > clarity about some of the important issues.https://quip.com/r69HA9GhGa7J (I apologize in advance if some of this was covered in previous discussions). 1. Since there's the Union type, it's also natural to have the Intersection type. A class is a subclass of Intersection[t1, t2, ...] if it's a subclass of all t1, t2 etc. The are 2 main uses of the Intersection type: a) Require that an argument implements multiple interfaces: class Foo: @abstractmethod def foo(self): ... class Bar: @abstractmethod def bar(self): ... def fooItWithABar(obj: Intersection[Foo, Bar]): ... b) Write the type of an overloaded function: @overload def foo(x: str) -> str: ... @overload def foo(x: bytes) -> bytes: ... foo # type: Intersection[Callable[[str], str], Callable[[bytes], bytes]] 2. Constrained type variables (Var('Y', t1, t2, ...)) have a very unusual behavior. a) "subclasses of t1 etc. are replaced by the most-derived base class among t1 etc." This defeats the very common use of constrained type variables: have a type preserving function limited to classes inherited from a common base. E.g. say we have a function: def relocate(e: Employee) -> Employee: ... The function actually always returns an object of the same type as the argument, so we want to write a more precise type. We usually do it like this: XEmployee = Var('XEmployee', Employee) def relocate(e: XEmployee) -> XEmployee: ... This won't work with the definition from the proposal. b) Multiple constraints introduce an implicit Union. I'd argue that type variables are more commonly constrained by an Intersection rather than a Union. So it will be more useful if given this definition Y has to be compatible with all of t1, t2 etc, rather than just one of them. Alternatively, this can be always spelled out explicitly: Y1 = Var('Y1', Union[t1, t2, ...]) Y2 = Var('Y2', Intersection[t1, t2, ...]) Pragmatics: 3. The names Union and Intersection are standard terminology in type checking, but may not be familiar to many Python users. Names like AnyOf[] and AllOf[] can be more intuitive. 4. Similar to allowing None to mean type(None) it's nice to have shortcuts like: (t1, t2, ...) == Tuple[t1, t2, ...] [t1] == List[t1] {t1: t2} == Dict[t1, t2] {t1} == Set[t1] The last 3 can be Sequence[t1], Mapping[t1, t2] and collections.Set[t1] if we want to encourage the use of abstract types. 5. Using strings for forward references can be messy in case of generics: parsing of brackets etc in the string will be needed. I propose explicit forward declarations: C = Declare('C') class C(Generic[X]): def foo(self, other: C[X]): ... def bar(self, other: C[Y]): ... 6. On the other hand, using strings for unconstrained type variables is quite handy, and doesn't share the same problem: def head(xs: List['T']) -> 'T': ... Regards, Eugene
- Previous message: [Python-ideas] Type Hinting Kick-off
- Next message: [Python-ideas] Type Hinting Kick-off
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
More information about the Python-ideas mailing list