[Zope-dev] summary of discussion was: adapter vs factory Re: implementing zope.component 4.0

Chris McDonough chrism at plope.com
Tue Dec 1 09:54:45 EST 2009


Martijn Faassen wrote:
> Hi there,
> 
> I'd like to summarize the options I've seen appear in the discussion so far.
> 
> We have the following options:
> 
> 1) introduce a new method, such as "instance()" or "lookup()" on 
> instance. It unifies utilities with adapters. We can make it do whatever 
> we want without worrying about backwards compatibility.
> 
> 2) introduce several new methods that distinguish between utility and 
> adapter lookup. We can make them do whatever we want without worrying 
> about backwards compatibility.
> 
> 3) call the interface, which unifies adapter and utility lookups. Use 
> tuples for multi adaptation. We think could make this work without *too* 
> much backwards compatibility issues (pending research on how prevalent 
> tuple adaptation really is). In the long term we can even map out a 
> deprecation strategy that can smoothly migrate us to a "multi argument" 
> approach.
> 
> 4) call the interface, which unifies adapter and utility lookups. Use 
> multiple arguments for multi adaptation. The backwards compatibility 
> obstacles are largest here as we already have the "default" argument. 
> We'd need to introduce multiple "modes" to selectively upgrade.
> 
> I'm in favor of calling the interface. I'm also in favor of unifying 
> adapter and utility lookup.
> 
> On the back end, I'm also in favor of allowing utility creation by 
> factory (or "null adaptation") and allowing instance lookup for 
> instances ("contextual utility lookup" or "adaptation to an instance"). 
>   I think four ways to retrieve an object of the right interface 
> (combining factory/registered instance and lookup globally/lookup for an 
> instance) is a good argument *against* distinguishing between creation 
> strategies or "connection to adapted object or not" in the API.
> 
> If I look up a utility I wouldn't want to care whether it happened to be 
> a previously registered instance or a factory created one. If I look up 
> an adapter I wouldn't care whether it happened to be a previously 
> registered instance either. In fact, returning a previously registered 
> instance can be very well implemented using a factory. (In fact, this 
> suggests to me we should actually explore implementing instance 
> registration in terms of special factories.)

I am also in favor of unifying adapter and utility lookup.  Or at least 
creating a more normalized API.

On the syntax of the change:

I am more or less somewhere between -0 and +0 on the idea of presenting a 
unified API as methods of interfaces (call or non-call).  While I don't think 
this idea is the worst idea in the world and it might be better than the 
current global API, I don't think we should *only* do this; similar changes 
should be made to the registry itself.  Code that uses the global API needs to 
do a registry lookup for each usage, so it's slower than code which doesn't. 
If interface methods become available to unify adapter and utility lookup, the 
same sorts of methods should be added to the registry itself for 
performance-sensitive code.  I also believe that code that locates a registry 
explicitly and calls lookup methods on it is easier to understand for the 
maintenance programmer than is an equivalent global API.

On the semantics of the change:

Personally I think that it's a fantasy to believe that the difference between 
an object created via a factory on-demand and an object simply returned should 
*never* matter to a caller.  You may not want the caller to need to care, and 
it may be inconvenient to take into account circumstances where the caller 
needs to care.  But because this is Python, the caller still often does need to 
care.

The only circumstance where a caller would *never* need to care would be when 
the object returned could be guaranteed to *never ever* have any methods called 
on it that weren't part of the interface defined by the interface being looked 
up.  If we want this, we should probably just be using Java.

I am extremely uncomfortable with any situation where:

   class IFoo(Interface):
       pass

   IFoo()

... does not result in any factory invocation.  I hope it's obvious why this is 
the case.

The current global API has a modicum "kindness" for maintenance developers 
because we *haven't* unified adapter and utility lookup in such a way.  They 
stand a shot at understanding that the result of getUtility usually has 
"lifetime A" and the result of getAdapter/getMultiAdapter has "lifetime B".  If 
we take out this safety belt, I'd lean towards more explicitness rather than 
less: let the caller call the result of the lookup.

- C


More information about the Zope-Dev mailing list