[Python-3000] Revised PEP 3119 (Abstract Base Classes)
talin at acm.org
Sat May 12 21:07:24 CEST 2007
Guido van Rossum wrote:
> Here's a new version of the ABC PEP. A lot has changed; a lot remains.
> I can't give a detailed overview of all the changes, and a diff would
> show too many spurious changes, but some of the highlights are:
Some general comments on the PEP:
Compared to the previous version, this version of the PEP is closer in
spirit to the various other competing proposals for 'post-hoc object
taxonomies', although some important differences remain. I'd like to
point out both the similarities and the differences, especially the
latter as they form the basis for further discussion and possibly evolution.
First, the ways in which the new PEP more closely resembles its competitors:
The new version of the PEP is more strongly oriented towards post-hoc
classification of objects, in other words, putting classes into
categories that may not have existed when the classes were created.
It also means that there is no longer a requirement that categories for
built-in objects have an official Python "seal of approval". Anyone can
come along and re-categorize the built-ins however they like; And they
can do so in a way that doesn't interfere with any previously existing
categories. There will of course be certain 'standard' categories (as
outlined in the PEP), but these standard categories do not have any
privileged status, unlike the ones in the earlier versions of the PEP.
It means that if we make a mistake defining the categories (or more
likely, if we fail to address someone's needs), it is possible for
someone else to come along and repair that mistake by defining a
The categorization relationships are now stored preferentially in a map
which is external to the objects being categorized, allowing objects to
be recategorized without mutating them. This is similar to the behavior
of Colin Winter's 'roles' proposal and some others.
(For the remainder of this document, I am going to use the term "dynamic
inheritance" to describe specifying inheritance via Guido's special
methods, as opposed to "traditional inheritance", what we have now.)
Now, on to the differences:
The key differentiator between Guido's proposal and the others can be
summarized by the following question: "Should the mechanism which
defines the hierarchy of classes be the same as the mechanism that
defines the hierarchy of categories?"
To put it another way, is a "category" (or "interface" or "role" or
whatever term you want to use) a "class" in the normal sense, or is it
some other thing?
In the terminology of Java and C# and other languages which support
interfaces, the term 'interface' is explicitly defined as something that
is 'not a class'. A class is a unit of implementation, and interfaces
contain no implementation. 
In these object classification systems, there are three different
relationships we care about:
-- The normal inheritance relationship between classes.
-- The specification of which classes belong to which categories.
-- The relationship between the categories themselves.
(Note that in some systems, such as Raymond Hettinger's attribute-based
proposal, the third type of relationship doesn't exist - each category
is standalone, although you can simulate the effects of a category
hierarchy by putting objects in multiple categories. Thus, there's no
MutableSequence category, but you can place an object in both Mutable
and Sequence and infer from there.)
Given these different types of relationships, the question to be asked
is, should all of these various things use the same mechanism and the
same testing predicate (isinstance), or should they be separate mechanisms?
I'll try to summarize some of the pros and cons, although this should
not be considered a comprehensive list:
Arguments in favor of reusing 'isinstance':
-- It's familiar and easy to remember.
-- Not everyone considers interfaces and implementations to be
distinct things, at least not in Python where there are no clear
boundaries enforced by the language (as can be seen in Guido's desire to
have some partial implementation in the ABCs.)
-- Declaring overloads in PJE's generic function proposal is cleaner
if we only have to worry about annotating arguments for types rather
than types + interfaces. In other words, we would need two different
kinds of annotations for a given method signature, and a way to
discriminate between them. If categories are just base classes, then we
only have one dispatch type to worry about. 
Arguments in favor of a different mechanism:
-- Mixing different kinds of inheritance mechanisms within a single
object might lead to some strange inconsistencies. For example, if you
have two classes, one which derives from an ABC using traditional
inheritance, and one which derives using dynamic inheritance, they may
(For example, the @abstractmethod decorator only affects classes
that derive from the ABC using traditional inheritance, not dynamic
inheritance. Some folks my find this inconsistency objectionable.)
-- For some people, an interface is not the same thing as a class,
and should not be treated as such. In particular, there is a desire by
some people to enforce a stricter separation between interface and
-- Forcing them to be separate allows you to make certain
simplifying assumptions about the class hierarchy. If categories can
relate to each other via traditional inheritance, and if I want to trace
upwards from a given class to find all interfaces that it implements,
then I may have to trace both traditional and dynamic inheritance links.
If categories can only relate via some special scheme, however, then I
can simply do my tracing in two passes: First find all base classes
using traditional inheritance, and then given that set, find all
categories using dynamic inheritance. In other words, I don't have to
keep switching inheritance types as I trace.
 On the other hand, both C# and Java allow interfaces to be tested by
their equivalent of "isinstance" so there is some conflation of the two.
On the gripping hand, however, C# and Java are both statically typed
language, where things like "isinstance" really means "istype", whereas
in Python "isinstance" really means something more like
"isimplementation". So there is no exact equivalent to what Python does
 I should mention that one of my personal criteria for evaluating
these proposals is the level of synergy achieved with PJE's PEP. Now,
PJE may claim that he doesn't need interfaces or ABCs or anything, but I
believe that his PEP benefits considerably by the existence of ABCs,
because it means that you need far fewer overloads in an ABC world.
Thus, I can overload based on "Sequence" rather than having to have
separate overloads for list, tuple, and various user-created sequence
types. (Although I can if I really need to.)
I would go further, and say that these object taxonomies should only go
so far as to provide what is needed to obtain that synergy; Any features
beyond that are mostly superfluous. But that's just my personal opinion.
More information about the Python-3000