On Sep 9, 2015, at 21:34, Jukka Lehtosalo <jlehtosalo@gmail.com> wrote:I'm not sure if I fully understand what you mean by implicit vs. explicit ABCs (and the static/runtime distinction). Could you define these terms and maybe give some examples of each?I just gave examples just one paragraph above.A (runtime) implicit ABC is something that uses a __subclasshook__ (usually implementing a structural check). So, for instance, any type that implements __iter__ is-a Iterable, e.g., according to isinstance or issubclass or @singledispatch, because that's what Iterable.__subclasshook__ checks for.A (runtime) explicit ABC is something that isn't implicit, like Sequence: no hook, so nothing is-a Sequence unless it either inherits the ABC or registers with it.You're proposing a parallel but separate distinction at static typing time. Any ABC that's a Protocol is checked based on a structural check; otherwise, it's checked based on inheritance.
This means it's now possible to create supertypes that are implicit at runtime but explicit at static typing time (which might occasionally be useful), or vice-versa (which I can't imagine why you'd ever want).
Besides the obvious negatives in having two not-quite-compatible and very-different-looking ways of expressing the same concept, this is going to lead to people wanting to know why their type checker is complaining about perfectly good code ("I tested that constant with isinstance, and it really is-a Spammable, and the type checker is inferring its type properly, and yet I get an error passing it to a function that wants a Spammable") or allowing blatantly invalid code ("I annotated my function to only take Spammable arguments, but someone is passing something that calls the fallback implementation of my singledispatch function instead of the Spammable overload").
Maybe the solution is to expand your proposal a little: make Protocol automatically create a __subclasshook__ (which you listed as an optional idea in the proposal), and also change all of the existing stdlib implicit ABCs to Protocols and scrap their manual hooks, and also update the relevant documentation (e.g., the abc module and the data model section on __subclasshook__) to recommend using Protocol instead of implementing a manual hook if the only thing you want is structural subtyping. Of course the backward compatibility isn't perfect (unless you want to manually munge up collections.abc when typing is imported), and people using legacy third-party code might need to add stubs (although that seems necessary anyway). But for most people, everything should just work as people expect. A type is either structurally typed or explicitly (via inheritance or registration) types, both at static typing time and a runtime, and that's always expressed by the name Protocol. (But for the rare cases when you really need a type check that's looser at runtime, you can still write a manual hook to handle that.)