[Python-Dev] re: *very* revised proposal for interfaces

John Williams jrw@pobox.com
Wed, 02 Oct 2002 14:55:58 -0500


Gerald S. Williams wrote:
 > This is along the lines of what I was suggesting. Note that
 > you can optionally do some argument list checking. You can
 > also check other properties but that requires you to check
 > against an instantiated object and indicate the presence of
 > these properties when instantiating an interface object.

I think we're trying to solve different problems.  You seem to want to
very that a class supports a certain set of methods, but I just want to
verify that the class *claims* to implement the interface and provide a
framework to make that happen, like a more automated version of PEP 245.

For my purposes, I'm not sure the error checking is really a Good Thing
after some of the things Esteban Castro pointed out.  If you fail to
implement the nesessary methods, that's your own problem.  This approach
is a lot less work for me, and handles strange cases of late binding
more gracefully.  Of course a warning would be helpful in the 95% of
cases where the assumptions made for error checking are correct.

 >>class C(object, I):
 >
 > ...
 >
 >>assert I not in C.__bases__ # Interfaces are not really base classes!
 >
 > Isn't this assertion going to fail the way you showed it?
 > Inheritance needn't be used at all for interfaces.

I use inheritence syntax for interfaces, since it's there and
convenient, but I wanted to emphasize that although interfaces can be
subclasses of interfaces, regular classes *cannot* be subclasses of
interfaces, even though the syntax makes it look that way.

It might be worthwhile to add an "implements(class, interface)"
function.  If you want to get fancy, let the first argument be an
instance as well, and let the second argument be a list of interfaces,
all of which must be supported (the opposite of isinstance's disjunctive
behavior!)

 > I don't think you need any magic class names. If a class
 > wants to present an interface, it can provide a derived
 > class and/or surrogate if needed. For example:
 >
 > class MyDerivedInterface(MyClass):
 >     def interface_name(self,x): return MyClass.my_name(self,x,1)
 >
 > class MySurrogateInterface(object):
 >     def __init__(self,me):      self.me = me
 >     def __getattr__(self,attr): return self.me.__getattribute__(attr)
 >     def interface_name(self,x): return self.me.my_name(x,1)

This only works when you can add methods to classes that implement the
interface.  It's a bit awkward for retrofitting classes you didn't
write, and just not possible for classes implmented in C, like the
builtin classes.

 >>d = D()
 >>i = I(d)     # Note i could really just be d here, not that it matters.
 >
 > But do interfaces really need to have this capability
 > built-in? If you want to present an interface that's
 > constrained, you can do it using a derived class or
 > surrogate. I would view "d" as the correct thing to
 > use in this example.

The idea of constraining i to only implement methods of I is something
from my original proposal that I've since decided was a bad idea--extra
work for no benefit.  The real issue here is that I(d) implements the
methods of interface I.  If class D implements the methods of I
directly, then I(d) can be d, but in normal use you won't know the class
of d, and a wrapper may be necessary, so you can't assume I(d) is d.

 > One thing my simplified example did not show (though
 > it was in my local versions) is the ability to have
 > implemented_by() register the interface in addition
 > to testing compliance. This requires something like
 > "implementerClass.__implements__ += interfaceClass"
 > (with the appropriate safety checks). This would
 > allow a more "contractual" approach to interfaces,
 > since you could check to see if a class has been
 > registered as supporting an interface before trying
 > to use that interface.

This is more like what I had in mind to do behind the scenes.

 > I think we're both saying the same thing--there is
 > a core issue that can be addressed without language
 > extensions or similar things that complicate the
 > implementation. But I have a more minimalist view:
 > don't impact anything if your class presents the
 > interface already. All you need is a simple means
 > to declare (and verify) that a class implements an
 > interface.

I think we're more in agreement than you think.  My original proposal
doesn't do what you're saying here, but the revised version with
slightly relaxed rules does, by allowing an object to be its own
wrapper/proxy when it implements the interface in the most
straightforward way, so the "wrapping" step (calling the interface
class) just reduces to a type assertion.

jw