[Python-Dev] re: very revised proposal for interfaces (original) (raw)

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