<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body dir="auto"><div>On Aug 16, 2014, at 8:02, Brett Cannon <<a href="mailto:brett@python.org">brett@python.org</a>> wrote:</div><div><br></div><blockquote type="cite"><div><div class="gmail_quote">On Sat Aug 16 2014 at 10:38:34 AM Andrew Barnert <<a href="mailto:abarnert@yahoo.com.dmarc.invalid">abarnert@yahoo.com.dmarc.invalid</a>> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div dir="auto"><div>On Aug 16, 2014, at 6:00, Dave Halter <<a href="mailto:davidhalter88@gmail.com" target="_blank">davidhalter88@gmail.com</a>> wrote:</div><div><br></div><blockquote type="cite"><div><div dir="ltr">
<div><div><b>Appendix (My Proposal)</b></div><div><div class="gmail_extra"><br></div><div class="gmail_extra">
My proposal (as discussed and evolved with a few good people at EuroPython) for containers would look something like this:</div><div class="gmail_extra"><br></div><div class="gmail_extra"> def foo(index: int, x: [float], y: {int: str}) -> (float, str):</div>
<div class="gmail_extra"> return x[index], y[index]</div><div class="gmail_extra"><br></div><div class="gmail_extra">The "default" containers (set, list, dict and tuple) would just serve as a way of specifying containers. This makes a lot of things less complicated:</div>
<div class="gmail_extra"><br></div><div class="gmail_extra">- It's easier to understand (everybody knows builtin types). It also feels natural to me. The example above covers also almost all variations. A tuple could be expanded by using the ellipsis: `(int, object, ..., float)`.</div>
- No imports needed. People are more likely to use it, if they don't have to import typing all the time. This is important for static analysis, people are only likely to use it if it's easier than writing docstrings with type information.<div class="gmail_extra">
- Argument clinic could use the same. The standard library quite often doesn't accept abstract data types, btw. </div><div class="gmail_extra">- It's what people sometimes use in docstrings: ``@rtype: (float, str)`` or ``:rtype: (float, str)``.</div>
<div class="gmail_extra"><br></div><div class="gmail_extra">I know this doesn't solve the duck typing issue, but if you look at real-life Python code bases, there are very few instances of actually implementing a ``Mapping``, etc. </div>
</div></div></div></div></blockquote><div><br></div></div><div dir="auto"><div>For "Mapping", maybe (although anyone who uses some form of tree-based mapping, either to avoid hash-collision attacks or because he needs sorting, may disagree).</div>
<div><br></div><div>But for "etc.", people implement them all the time. Especially "Iterable" and "Callable". And, even some of the ones that people don't implement often, they use often, implicitly or otherwise, like TextIOBase.</div>
<div><br></div><div>Anything that encourages people to restrict their code to only working on lists instead of iterables would be a huge step backward to Python 2.2. And your argument for it ("everybody knows builtin types") implies that's exactly what you're expecting with this proposal.</div>
<div><br></div><div>However, there's an easy way around this: just let [spam] in your syntax mean what Iterable[spam] means in MyPy's. If someone really needs to declare that they will only accept a list or whatever, that's the uncommon case, and can be written more verbosely. And I don't see any reason why this can't be added on top of genericizing the ABCs a la MyPy.</div>
<div><br></div><div>Meanwhile, your tuple doesn't fit the same pattern as the others, because it's explicitly fixed-size and heterogeneous. And I think this is a good thing. And I think it's pretty close to what MyPy does with an expression list of types already; if not, it seems like what MyPy _should_ do. If I loop over a zip of a [str] and an [int], the loop variable is a (str, int), not a Tuple[str or int].</div>
<div><br></div><div>So, making it easier to specify generic builtins is a bad idea, but using builtins to make it easier to specify common types is a great idea.</div></div></blockquote><div><br></div><div>The trick in all of this is making sure people instinctively know what the builtin types represent in terms of an interface w/o necessarily over-specifying. For instance, a list could be viewed as MutableSequence when all that is really necessary is Sequence or Iterable. Just think of those situations where a list or tuple both work as an argument; how do you specify that without assuming mutability? It's tricky to figure out what a proper assumption of what the built-ins represent should be. </div></div></div></blockquote><br><div>Honestly, I think [str] is the only case where this is an important question, so let's think about that rather than trying to think about a more general and abstract problem.</div><div><br></div><div>I'm not sure whether, when people say they need a list of strings, they more often mean Iterable[str] rather than Sequence[str] or MutableSequence[str]. I suspect it's the former, but I can't prove it, and I also suspect it's more of a 70/10/20 case than a 98/1/1 case. So maybe that argues that [str] just shouldn't be allowed.</div><div><br></div><div>But if it meant Iterable[str], someone who used it when they needed a Sequence or MutableSequence would get an error when they tried to MyPy their library, app, whatever. And it wouldn't be that hard to make that error explain the problem to them--the same way clang tries to explain template errors in C++ and suggest fixes, except that it would be orders of magnitude easier. "spam is an iterable, so you can't assign to its indexes. Did you mean to declare it as MutableSequence[str]?" On the other hand, if [str] meant MutableSequence[str] (or list[str]), the author who used it on a function that did nothing but loop over spam would not get an error; he'd have to wait until he published his code and someone filed a bug report saying "You declared spam as a MutableSequence, even though all you do is loop over it, and now my code that worked correctly with your spam-1.7, and that still works correctly with spam-1.8 if I don't use static checking, fails the linter. Did you mean to declare it as Iterable[str]?"</div><div><br></div><div>This obviously isn't a slam-sunk argument. If MutableSequence were used far more often than Iterable, or were more pythonic in some way, then it would make sense for [str] to mean MutableSequence despite the fact that it puts the errors in the less convenient place. But if they're both reasonably common, I think this argues for making it mean Iterable.</div><div><br></div><div>For the last part:</div><div><br></div><div><blockquote type="cite" style="-webkit-tap-highlight-color: rgba(26, 26, 26, 0.296875); -webkit-composition-fill-color: rgba(175, 192, 227, 0.230469); -webkit-composition-frame-color: rgba(77, 128, 180, 0.230469); "><div class="gmail_quote">Just think of those situations where a list or tuple both work as an argument; how do you specify that without assuming mutability?</div></blockquote><br></div><div>That one's easy: you write Sequence. A lot of similar questions were already answered when abc, Number, collections.abc, and io were designed, and they did a great job answering some tricky questions--which is exactly why I think static typing should use those already-worked-out cases rather than trying to answer all those questions again with a parallel type hierarchy. (And if use of static typing leads people to realize that one of those ABCs got something wrong, better to fix that bug in the ABC than to leave it incorrect and make the typing type different.)</div></body></html>