glyph at twistedmatrix.com
Tue Dec 15 14:26:59 EST 2009
On Dec 15, 2009, at 1:11 PM, Jared Gisin wrote:
> I completely fail to see why zope.interface is even needed. It's not Pythonic at all and it contributes to unnecessary code bloat.
Oh gosh! You're absolutely right! I never noticed it before! I just got out my Pythonic-o-meter and measured Zope Interface! Apparently it is only 0.44 vRossums! (For those you familiar only with the SI units, a vRossum is equivalent to one Microtim per cubic meter-second). We should totally delete all the interfaces in Twisted!
Wait, oops. I mean, did you even read <http://glyph.twistedmatrix.com/2009/02/explaining-why-interfaces-are-great.html>? There are lots of reasons to have interfaces.
> What's wrong with writing subclasses?
Lots of things in Twisted are subclasses. twisted.internet.protocol.Protocol provides a helpful utility base-class for implementing twisted.internet.interfaces.IProtocol. If you use them for what they're good for, there's nothing wrong with them.
But, as I said in my article, interfaces and classes are for different things.
As a very simple example of what's wrong with subclassing, there are times when having extra superclasses breaks things. For example: let's say that you want to have an IProtocol implementation that uses __slots__ and doesn't have a __dict__. Or, you want to do the equivalent thing in C to write a super-optimized IProtocol implementation.
If your documentation says "this parameter must be a Protocol", then you're stuck. There's no way to enforce that or provide friendly debugging error messages when you *don't* provide a Protocol; you just have to invoke the appropriate methods and hope it works. If you do actually subclass Protocol in your application, in the best case you get a class which accidentally inherits a __dict__, and in the worst case you get a base class layout conflict error and you can't even import your module. There are also lots of ways that metaclasses can conflict, inheritance hierarchies can become awkward and confusing, etc. This is even worse if the base class you want happens to do some unwanted work in its constructor.
Another use for interfaces is testing. For example, you can use interfaces to write tests to make sure that your code is up-to-date with the most recent specifications. Let's say that we have an interface, IFoo, that has a method, 'bar'. We want to add a method, 'baz', to it. Now, applications may be claiming to implement IFoo already, so we need to be careful when we invoke 'bar' as it may not be present, but the savvy implementor could use 'verifyObject' to make sure that their MyFoo class properly implemented all the required methods, and IFoo.
There are some things you can kinda-sorta do with metaclasses or introspection to provide similar functionality, but they're highly susceptible to implementation details shifting around. Metaclasses, in particular, tend to exacerbate the problems I mentioned above with inheritance conflicts and features like __slots__.
Yet another use for interfaces is adaptation. This is very useful in integration systems like twisted.cred. The interface object serves as a concise encapsulation of what the calling code wants to get out of cred, and realm implementations can return whatever.
> I've never had a case where that wasn't sufficient.
Your limited experience isn't necessarily a good argument for what Twisted should or shouldn't do. There are many people for whom the 'urllib' or 'socket' modules have always been sufficient, but that doesn't mean we're going to give up and go home either.
If you still don't think my reasoning is adequate, you should spend a few years contributing lots of really useful patches to Twisted, then bring this up again.
More information about the Twisted-Python