[Python-3000] Breakthrough in thinking about ABCs (PEPs 3119 and 3141) (original) (raw)

Guido van Rossum guido at python.org
Tue May 1 02:19:27 CEST 2007


After a couple of whiteboard discussions with Collin Winter and Jeffrey Jasskin I have a much better grip on where to go next with the ABC PEPs.

(a) Roles

Collin will continue to develop his Roles PEP. This may or may not end up providing a viable alternative to ABCs; in either case it will be refreshing to compare and contrast the two proposals.

(b) Overloading isinstance and issublcass

The idea of overloading isinstance and issubclass is running into some resistance. I still like it, but if there is overwhelming discomfort, we can change it so that instead of writing isinstance(x, C) or issubclass(D, C) (where C overloads these operations), you'd have to write something like C.hasinstance(x) or C.hassubclass(D), where hasinstance and hassubclass are defined by some ABC metaclass. I'd still like to have the spec for hasinstance and hassubclass in the core language, so that different 3rd party frameworks don't need to invent different ways of spelling this inquiry.

Personally, I still think that the most uniform way of spelling this is overloading isinstance and issubclass; that has the highest likelihood of standardizing the spelling for such inquiries. I'd like to avoid disasters such as Java's String.length vs. Vector.length() vs. Collection.size(). One observation is that in most cases isinstance and issubclass are used with a specific, known class as their second argument, so that the likelihood of breaking code by this overloading is minimal: the calls can be trusted as much as you trust the second argument. (I found only 4 uses of isinstance(x, ) amongst the first 50 hits in Google Code Search.)

However this turns out, it makes me ant to reduce the number of ABCs defined initially in the PEPs, as it will now be easy to define ABCs representing "less-powerful abstractions" and insert them into the right place in the ABC hierarchy by overloading either issubclass or the alternative hassubclass class method.

(c) ABCs as classes vs. ABCs as metaclasses

The original ABC PEPs naively use subclassing from ABCs only. This ran into trouble when someone observed that if classes C and D both inherit from TotallyOrdered, that doesn't mean that C() < D() is defined. (For a quick counterexample, consider that int and str are both total orders, but 42 < "a" raises TypeError.) Similar for Ring and other algebraic notions introduced in PEP 3141. The correct approach is for TotallyOrdered to be a metaclass (is this the typeclass thing in Haskell?). I expect that we'll leave them out of the ABC namespace for now and instead just spell out lt and le as operators defined by various classes. If you want TotallyOrdered, you can easily define it yourself, call TotallyOrdered.register(int) etc., and then isinstance(int, TotallyOrdered) (or TotallyOrdered.hasinstance(int)) will return True. OTOH, many of the classes proposed in PEP 3119 (e.g. Set, Sequence, Mapping) do make sense as base classes, and I don't expect to turn these into metaclasses.

(d) Comparing containers

I am retracting the idea of making all sequences comparable; instead, you can compare only list to list, tuple to tuple, str to str, etc. Ditto for concatenation. This means that eq and and are not part of the Sequence spec.

OTOH for sets, I think it makes sense to require all set implementations to be inter-comparable: an efficient default implementation can easily be provided, and since sets are a relatively new addition, there is no prior art of multiple incompatible set implementations in the core; to the contrary, the two built-in set types (set and frozenset) are fully interoperable (unlike sequences, of which there are many, and none of these are interoperable).

For mappings I'm on the fence; while it would be easy to formally define m1 == m2 <==> set(m1.items()) == set(m2.items()), and that would be relatively easy to compute using only traversal and getitem, I'm not so sure there is any use for this, and it does break with tradition (dict can't currently be compared to the various dbm-style classes).

(e) Numeric tower

Jeffrey will write up the detailed specs for the numeric tower. MonoidUnderPlus, Ring and other algebraic notions are gone. We will have abstract classes Integer <: Rational <: Real <: Complex <: Number (*); and concrete classes complex <: Complex, float <: Real, decimal.Decimal <: Real, int <: Integer. (No concrete implementations of Rational, but there are many 3rd prty ones to choose from.) We came up with a really clever way whereby the implementations of binary operations like add and radd in concrete classes should defer to their counterpart in the abstract base class instead of returning NotImplemented; the abstract base class can then (at least in most cases) do the right thing when mixed operations are attempted on two different concrete subclasses that don't know about each other (solving a dilemma about which I blabbered yesterday). This does mean that Integer...Number will be built-in.

(*) D <: C means that D is a subclass of C.

-- --Guido van Rossum (home page: http://www.python.org/~guido/)



More information about the Python-3000 mailing list