[Python-3000] PEP 3133: Introducing Roles

Guido van Rossum guido at python.org
Thu May 17 20:36:27 CEST 2007

On 5/17/07, Benji York <benji at benjiyork.com> wrote:
> > [PEP 3119]
>  > In classical OOP theory, invocation is the preferred usage pattern,
>  > and inspection is actively discouraged, being considered a relic of an
>  > earlier, procedural programming style.  However, in practice this view
>  > is simply too dogmatic and inflexible, and leads to a kind of design
>  > rigidity that is very much at odds with the dynamic nature of a
>  > language like Python.
> I disagree with the last sentance in the above paragraph.  While
> zope.interface has been shown (in a seperate message) to perform the
> same tasks as the "rolls" PEP (3133) and below I show the similarities
> between this PEP (ABCs) and zope.interface, I want to point out that
> users of zope.interface don't actually use it in these ways.

I'm not wedded to this sentence; the rationale didn't get a facelift
like the rest of the PEP. I do want to point out that other mechanisms
like GFs need to have access to isinstance/isclass or equivalent in
order to do their magic.

> So, what /do/ people use zope.interface for?  There are two primary
> uses: making contracts explicit and adaptation.  If more detail is
> desired about these uses; I'll be glad to share.

I know what they are. Adaptation is another area where isinstance or
equivalent is needed by the underlying machinery.

I do note that a fairly common place where *some* kind of type
checking (whether isinstance- or hasattr-based) is the implementation
of binary operators; a typical __add__ or __radd__ method usually
starts by testing whether the other argument is an object it
understands, and if not, it returns NotImplemented. Since this is
essentially *implementing* a (limited) GF strategy, I don't see how
adaptation or GFs will help to eliminate such type checks.

> My main point is that the time machine worked; people have had the moral
> equivalent of ABCs and Roles for years and have decided against using
> them the way the PEPs envision.

It's not the only way the PEP envisions they are used, and no longer
the major way. I expect that the uses you mention are actually more
important. And given that people want these I think it would be useful
to have them in the standard library.

> Of course if people still think ABCs
> are keen, then a stand-alone package can be created and we can see if
> there is uptake, if so; it can be added to the standard library later.

I want to add something to the standard library now, because it's been
relegated to 3rd party status for too long. However, I think I can do
better than zope.interface; in some cases I just disagree with its
design choices, on other cases I can change the language to improve
upon the contortions that zope had to go through to make things look
right. (E.g. overloading isinstance, keyword arguments to class
declarations, class decorators.) I am also leaving some of the more
esoteric parts of zope.interface out (e.g. assertions about
instances), but the mechanism I am proposing (isinstance overloading)
supports this just fine.

> If I recall correctly, the original motivation for ABCs was that some
> times people want to "sniff" an object and see what it is, almost always
> to dispatch appropriately.  That use case of "dispatch in the small",
> would seem to me to be much better addressed by generic functions.  If
> those generic functions want something in addition to classes to
> dispatch on, then interfaces can be used too.

That's just one motivation. Another, more important motivation is to
have something that can fulfill the role that zope.interfaces
fulfills, but with fewer arbitrary differences from what we already
know, a class hierarchy.

> If GF aren't desirable for that use case, then basefile, basesequence,
> and basemapping can be added to Python and cover 90% of what people
> need.  I think the Java Collections system has shown that it's not
> neccesary to provide all interfaces for all people.  If you can only
> provide a subset of an interface, make unimplemented methods raise
> NotImplementedError.

The ABC PEP currently defines fewer ABCs than the Java Collections
system, so I'm not sure what you're worried about.

>  > Overloading ``isinstance()`` and ``issubclass()``
>  > -------------------------------------------------
> Perhaps the PEP should just be reduced to include only this section.

And require every 3rd party library to invent its own notions of
sequence, mapping etc.? No way!

> Sidebar: this highlights one of the reasons zope.interface users employ
> the naming convention of prefixing their interface names with "I", it
> helps keep interface names short while giving you an easy name for
> "interface that corresponds to things of class Foo", which would be
> IFoo.

Yeah, that is out of necessity because zope forces you to have a
separate interface and implementation class. The ABC proposal does
away with this silly duplicate hierarchy.

>  >     assert issubclass(list, MyClass)
>      assert MyClassInterface.implementedBy(list)
>  >     assert issubclass(list, MyABC)
>      assert MyClassInterface.extends(MyInterface)
>  > You can also register another ABC::
>  >
>  >     class AnotherClass(metaclass=ABCMeta):
>  >         pass
>      class AnotherInterface(zope.interface.Interface):
>          pass
>  >     AnotherClass.register(basestring)
>      zope.interface.classImplements(basestring, AnotherInterface)
>  >     MyClass.register(AnotherClass)
> I don't quite understand the intent of the above line.  It appears to be
> extending the contract that AnotherClass embodies to promise to fulfill
> any contract that MyClass embodies.  That seems to be an unusual thing
> to want to express.

MyClass is meant to be an ABC here whose contract is weaker than that
of AnotherClass. Suppose there was only a built-in MutableSequence,
but a 3rd party needed a Sequence interface that didn't need to be
mutable. It could use this example, with AnotherClass being the
built-in MutableSequence, and MyClass being the 3rd party's Sequence

> Although unusual, you could still do it using
> zope.interface.  One way would be to add MyClassInterface to the
> __bases__ of AnotherInterface.
> OTOH, I might be confused by the colapsing of the class and interface
> hierarchies.  Do the classes in the above line of code represent the
> implementation or specification?


> [snip]
>  > ABCs for Containers and Iterators
>  > ---------------------------------
> zope.interface defines similar interfaces.  Surprisingly they aren't
> used all that often.  They can be viewed at
> http://svn.zope.org/zope.interface/trunk/src/zope/interface/common/.
> The files mapping.py, sequence.py, and idatetime.py are the most
> interesting.

I believe I worked for Zope Corp around the time these were designed.
I remember it was pretty painful to agree on which methods to include
or exclude. Having this decided by the standard library would solve
the problem by fiat for a larger audience.

> [snip rest]
> > I was just
> > thinking of how to "sell" ABCs as an alternative to current happy
> > users of zope.interfaces.
> One of the things that makes zope.interface users happy is the
> separation of specification and implementation.  The increasing
> separation of specification from implementation is what has
> driven Abstract Data Types in procedural languages, encapsulation
> in OOP, and now zope.interface.  Mixing the two back together in
> ABCs doesn't seem attractive.

This is a self-selecting audience -- people who see it differently
(like me) aren't likely to use zope.interface, or might be hoping for
something better.

> As for "selling" current users on an alternative, why bother?  If people
> need interfaces, they know where to find them.  I suspect I'm confused
> as to the intent of this discussion.

Many people have a strong preference for standard features over 3rd
party features, everything else being equal -- or even if everything
else isn't quite equal (but mostly so). A feature-by-feature
comparison between zope.interface and ABCs is helpful for people who
aren't yet current zope.interface users. it seems that in the balance,
we have:

- ABCs have support in the standard library

- ABCs don't force you to separate specification from implementation.
This counts as a pro for some, a con for others

- ABCs (out of the box) don't let you make assertions about instances.
This is a con for those who need that feature,  but I haven't met many
of those.

- With ABCs, the spelling of "does this object conform to this
interface" and "does this object inherit implementation from this
class" is the same (isinstance()). This counts as a pro for some, a
con for others. IMO it's mostly emotional and there is no rational
reason to worry about the spelling being the same.

I won't be offended if the authors and users of zope.interface decide
to ignore the ABCs in the standard library; the rest of us will still
benefit from them (and from GFs). However, I fully expect that
zope.interface will embrace at least some of the mechanisms added to
Py3k in support of ABCs, as they make implementing zope.interface
easier too. Also, if we add standard GFs, zope.interface will want to
work closely with those.

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

More information about the Python-3000 mailing list