[Python-Dev] *very* revised proposal for interfaces
Chermside, Michael
mchermside@ingdirect.com
Wed, 2 Oct 2002 16:27:31 -0400
[Please excuse poor email format... I've just been moved=20
to outlook and haven't yet figured out how to make it
behave like a normal email program.]
John, I really like your proposal!!!
The main thing that I like about it is that, as you say:
"It's also a lot easier to explain"
That's usually a sign of a good design... when it all falls
into place and becomes simple. I will admit, I've been trying
to follow the various interface suggestions and have mostly
been getting confused. This is simple and elegant, even if
a few bits would improve with tweaking.
Here is a running commentary on things I liked and disliked:
1. You create a new built-in type called "interface" with the
special property that it does NOT appear in __bases__ even
if declared to do so.
I like this. Your syntax for the most common case of=20
supporting an interface looks like this:
class C(object, I):
<... code here ...>
If we DIDN'T create a "special" type (special because Python
has to omit pure interfaces in generating __bases__), then
things could still work by some sort of declaration after C
is created:
class C(object):
<... code here ...>
declareItImplements(C,I)
But that's putting it in the wrong place. The declaration to
support an interface should be easy to type and to read (in the=20
common case), and should come at the TOP of the declaration of
the class, not the end. So I like this.
2. You have a "magic class" __binding__.
This sounds odd. Python hasn't ever used a "magic class" before.
But it certainly makes the syntax simple. After all, you need
to define a bunch of methods (the methods needed to conform to
the interface). Declaring a class is the handy way to define a
bunch of methods. So I think this is a little weird, but I don't
really object. If there's another solution, though, I'd like to
hear it.
3. Where does the "binding" live?
Creating some sort of "global binding registry" is really not
a good idea. Global is just bad, it becomes hard to find where
things were set, which causes mysterious code failures, and so
forth. At first, that's what I thought you were doing, but a
closer look changed my mind.
It seems to me that when you create a magic "__binding__" class
what you are ACTUALLY doing is adding to a list of "classes
implementing it" which is maintained in and associated with I,=20
the interface object. That has ABSOLUTELY NO effect on anyone
who is not using the interface, and it feels like the "right"
place to store this information. So I if I understand this
correctly, I like it.
4. You make use of the interface by invoking it on an object:
i =3D I(d)
This has been discussed before, and it's a good approach. It
allows for interfaces to return the object (thus not creating
extra objects unnecessarily) or a proxy (thus giving lots of
extra flexibility). Solidly supported.
5. You do NOT provide a way to do type declarations along with the
interface.
Python isn't picky about types, it naturally supports a policy=20
of allowing you to use any object that will do the job. That's
a good thing for the language (even if my own preferences tend=20
toward a stricter typing system) and interfaces aren't about
undermining it... just strengthening it! So +1 here.
6. You do NOT provide a way to declare preconditions, postconditions,
or anything like this for the methods. In fact, there's no
specification other than a docstring.
For this I'm not sure. I like the minimalistic, simple approach
of just giving a docstring, but I might also like some of the
power of extra features. If I have to give up extra power to get
a simple, workable approach then I'll live with it.
7. There's no way to "extend" interfaces, since inheriting from an
interface means something different.
That's OK with me -- seems like something one would only do when
in a severe meta-programming mood.
So all in all, I'm liking what I'm seeing here.
-- Michael Chermside
=20