[Zope-dev] A summary of "Interfaces vs ZCA concepts"

Thomas Lotze tl at gocept.com
Mon Dec 21 05:26:21 EST 2009


Hi,

this is a long message with a lot of replies to things that I don't agree
with. Since I realize that making those points over and over again doesn't
get us anywhere, I'd like to point out first that I'm going to implement
Martijn's suggestions anyway on one of my branches, hoping that seeing
more actual code to talk about might help getting to more consensus.

Martijn Faassen wrote:

>>> * It'd be nice if __call__ came back with a LookupError instead of a
>>> TypeError, but how to get from A to B without breakage?
>> 
>> It's not possible without breakage.
> 
> Unless we create a zope.interface specific LookupError which subclasses
> both the built-in LookupError and TypeError. zope.component's
> ComponentLookupError should subclass this special LookupError then.

Technically true, so my statement was admittedly too strong. I just don't
feel comfortable with the idea, which may well be just because it's the
"let's make both exceptions work sowmehow" solution to me instead of the
clear change I thought we were considering. OTOH, it's not that big an
issue either, so I guess I'd be fine with it.

>>> * the methods can be on zope.interface even if zope.component isn't
>>> installed. They will behave as if the component registry is empty.
>> 
>> This isn't covered by the consensus you mentioned above as far as I'm
>> concerned.
> 
> Yeah, I put that in so we can reach consensus on it. I thought Tres had a
> good idea going on there that makes the plugin behavior a lot cleaner.

Hm, I can't help feeling pushed into this. While this plugin stuff is
indeed nice *assuming* that we want all the zope.component concepts in
zope.interface, it doesn't contribute to the decision about *whether* we
want that in the first place.

>>> IFoo.adapt(context) raises LookupError, unless the context provides
>>> IFoo, in which case it returns context.
>>>
>>> IFoo.adapt(context, default=default) returns default unless context
>>> provides IFoo, in which case it returns context.
>>>
>>> IFoo.utility() raises LookupError.
>>
>> IFoo.utility(default=default) returns default
>> 
>> I think looking at that API explains why we have trouble with having
>> stub methods defined by zope.interface: these methods contain enough
>> information about component concepts to blur the distinction between
>> zope.interface and zope.component, but they still lie about the actual
>> method signature.
>
> I don't understand you: why do you say they lie about their method
> signature? They should have the same signature and have a well-defined
> behavior if zope.component is not installed: there is nothing registered
> at all. zope.interface provides a plugin point that allows one to plug
> lookup behavior into it.

When I wrote that, I was assuming that we were talking about patching
interfaces with methods that have zope.component's full lookup semantics,
including `name` and `context` parameters - which abviously would change
the signatures. If we're talking about something that doesn't add those
parameters, there's no lie involved but I don't see how our lookup methods
could then access the full feature set of zope.component's lookups.

> In that case, I want the real contract to be in zope.interface. That's
> where the methods are, after all. We need to talk about the concept of an
> adapter and a utility briefly in zope.interface and defer to
> zope.component as the most common implementation. We already have this
> kind of behavior going on anyway with __call__() (even though not
> documented!).

Well, we obviously disagree completely about this. The existing __call__
method is neither a good example of a zope.component lookup API, nor do I
think that it was fortunate to wire up the adaptation concept in
zope.interface through __call__ in the first place. I'd rather try to
loosen this reference to component concepts than use it as a reason for
adding more.

> You'll have to go into more detail. Why does it feel wrong to you?

Because it is just another way of encoding the zope.component details
within zope.interface. I would love to add a plugin API that is generic
enough to apply equally to other uses of interfaces than component lookup,
and that would allow implementations of component lookup with different
concepts and different lookup methods than those of zope.component.

> Why is it a problem that the zope.interface package gains knowledge about
> adaptation (which it always had, anyway)

(and which, IMO, it shouldn't have in the first place)

> and utility lookup?

Because if we're serious about making interfaces more of a language
feature, they should at their core be reduced to *being* mostly
information (maybe with a bit of verification code) instead of extended to
*doing* things that derive mainly from *our* particular ways of using them.

> Because to
> the user of those methods on Interface, it looks exactly like the
> packa
> does have such knowledge. We shouldn't lie.ge

I don't think that we lie as long as we state that we have a plugin system
of any kind (including monkey-patching, for the sake of discussion).
Speaking about lies again, I also consider it a kind of lie to say that we
provide a plugin system if it turns out in the end that it isn't much good
for anything but the one particular plugin provided by zope.component.

> In fact, let me propose the following plugin point instead, reducing it to
> a single method:
> 
> class ILookupPlugin(Interface):
>     def lookup(interface, contexts):
>          """Look up an object that provides interface, given contexts.
> 
>          contexts may be an empty list, or contain one or more entries.
> 
>          Raises LookupError if an object providing the interface cannot be
>          found.
>          """
> 
> Then __call__ and adapt and utility can be implemented by using
> "lookup()". Anything plugging into zope.interface would then have to only
> plug in a single method.

Would this in your mind still include a list of hooks whose behaviour
needs to be coordinated by the Interface methods (which affects at least
how exceptions are caught or propagated), or are we talking about a single
plugin being registered at a time? I'd prefer the latter as it's more
straight-forward. Or are there really compelling use cases for registering
more than one hook at the same time?

-- 
Thomas





More information about the Zope-Dev mailing list