<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">Things are looking up. I think we're down to a very small number of issues where we still disagree -- hopefully you'll allow me some leeway. :-)<br><br>On Thu, May 21, 2015 at 8:45 AM, Mark Shannon <span dir="ltr"><<a href="mailto:mark@hotpy.org" target="_blank">mark@hotpy.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span class=""><br>
<br>
On 21/05/15 16:01, Guido van Rossum wrote:<br>
</span><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span class="">
Hi Mark,<br>
<br>
We're down to the last few items here. I'm CC'ing python-dev so folks<br>
can see how close we are. I'll answer point by point.<br>
<br>
On Thu, May 21, 2015 at 6:24 AM, Mark Shannon <<a href="mailto:mark@hotpy.org" target="_blank">mark@hotpy.org</a><br></span><span class="">
<mailto:<a href="mailto:mark@hotpy.org" target="_blank">mark@hotpy.org</a>>> wrote:<br>
<br>
Hi,<br>
<br>
The PEP itself is looking fairly good.<br>
<br>
<br>
I hope you'll accept it at least provisionally so we can iterate over<br>
the finer points while a prototype of typing.py in in beta 1.<br>
<br>
However, I don't think that typing.py is ready yet, for a number of<br>
reasons:<br>
<br>
1.<br>
As I've said before, there needs to be a distinction between classes<br>
and types.<br>
They is no need for Any, Generic, Generic's subtypes, or Union to<br>
subclass builtins.type.<br>
<br>
<br>
I strongly disagree. They can appear in many positions where real<br>
classes are acceptable, in particular annotations can have classes (e.g.<br>
int) or types (e.g. Union[int, str]).<br>
</span></blockquote>
<br>
Why does this mean that they have to be classes? Annotations can be any object.<br></blockquote><div><br></div><div>I want to encourage users to think about annotations as types, and for most users the distinction between type and class is too subtle, so a simpler rule is to say they are classes. This works out nicely when the annotations are simple types such as 'int' or 'str' or user-defined classes (e.g. 'Employee').<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
It might to help to think, not in terms of types being classes, but classes being shorthand for the nominal type for that class (from the point of view of the checker and type geeks)<br>
So when the checker sees 'int' it treats it as Type(int).<br></blockquote><div><br></div><div>I'm fine with that being the formal interpretation (except that I don't want to introduce a function named Type()). But it's too subtle for most users.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
Subtyping is distinct from subclassing;<br>
Type(int) <: Union[Type(int), Type(str)]<br>
has no parallel in subclassing.<br>
There is no class that corresponds to a Union, Any or a Generic.<br></blockquote><div><br></div><div>Again, for most people te distinction is too subtle. People expect to be able to play around with things interactively. I think it will be helpful if they can experiment with the objects exported by typing too: experimenting with things like isinstance(42, Union[int, str]) or issubclass(Any, Employee) and issubclass(Employee, Any) is a useful thing to explore how these things work (always with the caveat that when Any is involved, issubclass is not transitive). Of course it won't work when they advance to type variables -- at that point you just *have* to understand the theory and switch from using the interactive interpreter to writing small test programs and seeing how mypy (or some other checker) responds to them.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
In order to support the<br>
class C(ParameterType[T]): pass<br></blockquote><div><br></div><div>I presume you mean class C(Generic[T])?<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
syntax, parametric types do indeed need to be classes, but Python has multiple inheritance, so thats not a problem:<br>
class ParameterType(type, Type): ...<br>
Otherwise typing.Types shouldn't be builtin.types and vice versa.<br></blockquote><div><br></div><div>There's one thing here that Jukka has convinced me of. While I really want Union[...] to act like a class (though not subclassable!), plain Union (without the [...]) needn't. The same is true for Callable and Tuple without [...]. I've filed <a href="https://github.com/ambv/typehinting/issues/133">https://github.com/ambv/typehinting/issues/133</a> for this. I'm not sure how much work it will be to fix this but I don't think it absolutely needs to be done in beta 1 -- there's not much you can do with them anyway.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
I think a lot of this issues on the tracker would not have been issues had the distinction been more clearly enforced.<span class=""><br>
<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
Playing around with typing.py, it has also become clear to me that it<br>
is also important to distinguish type constructors from types.<br>
<br>
What do I mean by a type constructor?<br>
A type constructor makes types.<br>
"List" is an example of a type constructor. It constructs types such<br>
as List[T] and List[int].<br>
Saying that something is a List (as opposed to a list) should be<br>
rejected.<br>
<br>
<br>
The PEP actually says that plain List (etc.) is equivalent to List[Any].<br>
(Well, at least that's the intention; it's implied by the section about<br>
the equivalence between Node() and Node[Any]().<br>
</blockquote>
<br></span>
Perhaps we should change that. Using 'List', rather than 'list' or 'List[Any]' suggests an error, or misunderstanding, to me.<br>
<br>
Is there a use case where 'List' is needed, and 'list' will not suffice?<br>
I'm assuming that the type checker knows that 'list' is a MutableSequence.<br><div><div class="h5"></div></div></blockquote><div><br></div><div>I think it's easier if we ask people to always write 'List' rather than 'list' when they are talking about types, and 'List[Any]' will probably be a popular type (lots of people don't want to think about exactly what the item type is, but they are sure that the container is a list).<br><br></div><div>There's also an argument from consistency with the collection ABCs. As you know, typing defines a bunch of types that act as "stand ins" for the corresponding ABCs defined in collections.abc (Iterable, Sequence, Sized, etc.). The intention here is that anywhere one of the collection ABCs is valid it should be okay to use the corresponding class imported from typing -- so that if you have code that currently uses "from collections.abc import Sequence, Mapping" you can just replace that with "from typing import Sequence, Mapping" and your code will still work. (You can then iterate at leisure on parametrizing the types.)<br><br></div><div>So we can use e.g. Sequence as a base class and it means the same as Sequence[Any]. Given this rule, it would be somewhat surprising if you couldn't use List but were forced to write List[Any] in other places. (Neither Sequence[Any] nor List[Any] can be instantiated so that's not a concern.)<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div><div class="h5">
<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
2.<br>
Usability of typing as it stands:<br>
<br>
Let's try to make a class that implements a mutable mapping.<br>
<br>
>>> import typing as tp<br>
#Make some variables.<br>
>>> T = tp.TypeVar('T')<br>
>>> K = tp.TypeVar('K')<br>
>>> V = tp.TypeVar('V')<br>
<br>
#Then make our class:<br>
<br>
>>> class MM(tp.MutableMapping): pass<br>
...<br>
#Oh that worked, but it shouldn't. MutableMapping is a type constructor.<br>
<br>
<br>
It means MutableMapping[Any].<br>
<br>
#Let's make one<br>
>>> MM()<br>
Traceback (most recent call last):<br>
File "<stdin>", line 1, in <module><br>
File "/home/mark/repositories/typehinting/prototyping/typing.py",<br>
line 1095, in __new__<br>
if _gorg(c) is Generic:<br>
File "/home/mark/repositories/typehinting/prototyping/typing.py",<br>
line 887, in _gorg<br>
while a.__origin__ is not None:<br>
AttributeError: type object 'Sized' has no attribute '__origin__'<br>
<br>
# ???<br>
<br>
<br>
Sorry, that's a bug I introduced in literally the last change to<br>
typing.py. I will fix it. The expected behavior is<br>
<br>
TypeError: Can't instantiate abstract class MM with abstract methods __len__<br>
<br>
#Well let's try using type variables.<br>
class MM2(tp.MutableMapping[K, V]): pass<br>
...<br>
>>> MM2()<br>
Traceback (most recent call last):<br>
File "<stdin>", line 1, in <module><br>
File "/home/mark/repositories/typehinting/prototyping/typing.py",<br>
line 1095, in __new__<br>
if _gorg(c) is Generic:<br>
File "/home/mark/repositories/typehinting/prototyping/typing.py",<br>
line 887, in _gorg<br>
while a.__origin__ is not None:<br>
AttributeError: type object 'Sized' has no attribute '__origin__'<br>
<br>
<br>
Ditto, and sorry.<br>
</blockquote></div></div>
No need to apologise, I'm just a bit worried about how easy it was for me to expose this sort of bug.<span class=""><br></span></blockquote><div><br></div><div>Well, I'm just glad you exposed it so soon after I introduced it. :-)<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span class="">
<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
<br>
At this point, we have to resort to using 'Dict', which forces us to<br>
subclass 'dict' which may not be what we want as it may cause<br>
metaclass conflicts.<br>
<br>
3.<br>
Memory consumption is also a worry. There is no caching, which means<br>
every time I use "List[int]" as an annotation, a new class object is<br>
created. Each class may only be a few KB, but collectively this<br>
could easily add up to several MBs.<br>
This should be easy to fix.<br>
<br>
<br>
I can work on this after the beta-1 release. Until then, type aliases<br>
can be used to avoid redundant type creation (and often they are clearer<br>
anyway :-).<br>
</blockquote></span>
Sure.<br></blockquote><div><br></div><div>OK. Tracking this in <a href="https://github.com/ambv/typehinting/issues/130">https://github.com/ambv/typehinting/issues/130</a><br><br>[...]<br clear="all"></div></div><br>-- <br><div class="gmail_signature">--Guido van Rossum (<a href="http://python.org/~guido" target="_blank">python.org/~guido</a>)</div>
</div></div>