<div dir="ltr"><div>Hi Mark,<br><br></div>We're down to the last few items here. I'm CC'ing python-dev so folks can see how close we are. I'll answer point by point.<br><div class="gmail_extra"><br><div class="gmail_quote">On Thu, May 21, 2015 at 6:24 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">Hi,<br>
<br>
The PEP itself is looking fairly good.<br></blockquote><div><br></div><div>I hope you'll accept it at least provisionally so we can iterate over the finer points while a prototype of typing.py in in beta 1.<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">
However, I don't think that typing.py is ready yet, for a number of reasons:<br>
<br>
1.<br>
As I've said before, there needs to be a distinction between classes and types.<br>
They is no need for Any, Generic, Generic's subtypes, or Union to subclass builtins.type.<br></blockquote><div><br></div><div>I strongly disagree. They can appear in many positions where real classes are acceptable, in particular annotations can have classes (e.g. int) or types (e.g. Union[int, str]).<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">
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 as List[T] and List[int].<br>
Saying that something is a List (as opposed to a list) should be rejected.<br></blockquote><div><br></div><div>The PEP actually says that plain List (etc.) is equivalent to List[Any]. (Well, at least that's the intention; it's implied by the section about the equivalence between Node() and Node[Any]().<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">
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></blockquote><div><br></div><div>It means MutableMapping[Any].<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">
#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", line 1095, in __new__<br>
    if _gorg(c) is Generic:<br>
  File "/home/mark/repositories/typehinting/prototyping/typing.py", line 887, in _gorg<br>
    while a.__origin__ is not None:<br>
AttributeError: type object 'Sized' has no attribute '__origin__'<br>
<br>
# ???<br></blockquote><div><br></div><div>Sorry, that's a bug I introduced in literally the last change to 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></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">
#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", line 1095, in __new__<br>
    if _gorg(c) is Generic:<br>
  File "/home/mark/repositories/typehinting/prototyping/typing.py", line 887, in _gorg<br>
    while a.__origin__ is not None:<br>
AttributeError: type object 'Sized' has no attribute '__origin__'<br></blockquote><div><br></div><div>Ditto, and sorry. <br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
At this point, we have to resort to using 'Dict', which forces us to subclass 'dict' which may not be what we want as it may cause metaclass conflicts.<br>
<br>
3.<br>
Memory consumption is also a worry. There is no caching, which means every time I use "List[int]" as an annotation, a new class object is created. Each class may only be a few KB, but collectively this could easily add up to several MBs.<br>
This should be easy to fix.<br></blockquote><div><br></div><div>I can work on this after the beta-1 release. Until then, type aliases can be used to avoid redundant type creation (and often they are clearer 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">
4.<br>
PY2, etc. really need to go.<br>
Assuming that this code type checks OK:<br>
<br>
 if typing.PY2:<br>
     type_safe_under_py2_only()<br>
 else:<br>
     type_safe_under_py3_only()<br>
<br>
Is the checker supposed to pass this:<br>
<br>
 if sys.hexversion < 0x03000000:<br>
     type_safe_under_py2_only()<br>
 else:<br>
     type_safe_under_py3_only()<br>
<br>
If it should pass, then why have PY2, etc. at all.<br>
If it should fail, well that is just stupid and annoying.<br>
<br>
Pylint already understands version checks, as does our (Semmle's) checker. I suspect most IDEs do as well.<br></blockquote><div><br></div><div>I have to negotiate this with Jukka but I think he'll agree.<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">
5.<br>
Removing isinstance() support:<br>
<br>
As I said before, this is the job of a checker not typing.py.<br>
<br>
It also introduces some strange situations:<br>
D = tp.Dict[str,int]<br>
d = {}<br>
assert isinstance(d, D)<br>
d["x"] = None<br>
assert isinstance(d, D)<br>
<br>
In the above case the first check passes, and the second fails.<br>
But d is either of type D or it isn't. It can't be both, as types<br>
are static properties of programs, unlike classes.<br></blockquote><div><br></div><div>Well, isinstance() is a dynamic function. The type checker has no authority over its behavior beyond its signature.<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">
And it's broken anyway:<br>
>>> D = tp.Dict[str,'D']<br>
>>> d = {"x": {}}<br>
>>> isinstance(d, D)<br>
False<br></blockquote><div><br></div><div>That's because _ForwardRef doesn't implement __instancheck__ or __subclasscheck__. It's easily fixed.<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
Realistically, I don't see typing.py being ready in time for 3.5.<br>
I'd be happy to be proved wrong.<br>
<br>
Cheers,<br>
Mark.<br>
<br>
<br>
P.S.<br>
I am worried by the lack of formal specification. It all seems a bit hand-waving. A formal spec reduces the likelihood of some unforeseen corner case being a permanent wart.<br></blockquote><div><br></div><div>Formal specs are not my cup of tea. :-( (I'm not proud of this, but it just is a fact -- see how terrible a job I've done of the Python reference manual.) The best I could come up with is PEP 483.<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">
Take the recursive type above. There is no mention of recursive types in the PEP and they are clearly possible. Are they allowed?<br></blockquote><div><br></div><div>They should be allowed. I imagine you could create one for which a naive  isinstance() imeplementation ends up in an infinite loop. That can be fixed too (we fixed this for printing self-referential lists and dicts).<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'm guessing that Jukka's thesis should cover a lot of this.<br>
Has it been published yet?<br>
</blockquote></div><br></div><div class="gmail_extra">Hopefully Jukka can answer that. :-)<br clear="all"></div><div class="gmail_extra"><br>-- <br><div class="gmail_signature">--Guido van Rossum (<a href="http://python.org/~guido" target="_blank">python.org/~guido</a>)</div>
</div></div>