Chris McDonough wrote:
> 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 think it's okay for us to say: if you call a method on something that 
you retrieved by interface that isn't actually specified to be on that 
interface, you're on your own. It may work, but it's not specified to 
work by the system you're using.

I'm not sure why lifetime issues are considered so important here. Of 
course they sometimes matter. But we use ORMs all the time. We create 
traversal hierarchies on the fly all the time. What's different in this 

If I want to index an object, do I care whether the catalog was just 
created on the fly and it's talking to a relational database?

I think you're arguing that because abstractions are sometimes leaky 
(lifetime issues) we shouldn't have this abstraction at all. Why is the 
leakiness so important here?

> 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.

I think there are two centers of attraction for unification:

* everything is a factory. If I want to look up an instance, I look up a 
factory that returns me the same instance all the time. I.e. IFoo() and 

* everything is an instance. If I want to call a factory, I look up an 
instance that is a factory, and call it. I.e. IFoo.lookup() and 

zope.component presents a compromise between those positions.

The advantage I see of unifying towards factories is a less verbose API 
for common operations than an explicit API would have.

If you take the utilities come from a factory approach, this would 
suggest an API like this (on Interface):

def __call__(self, arg=()):
     if not isinstance(arg, tuple):
         arg = (arg,)
     return self.factory(arg)(*arg)

# low level
def factory(self, arg=()):
     return registry.lookup(from_=arg, to=self)

The drawback is that while you *can* register utilities as non-factories 
and look them up, you'd do it through 'factory', as the real way to look 
up utilities would be to call a factory.

If you take the utilities are registered instances, that would suggest 
an API like this:

# convenience
def __call__(self, arg=()):
     if not isinstance(arg, tuple):
         arg = (arg,)
     return self.lookup(arg)(*arg)

def lookup(self, arg=()):
    return registry.lookup(from_=arg, to=self)

You'd register utilities as instances directly and look them up using 
lookup(). The convenience method still works for adapters.

The drawback is that IFoo() would result in IFoo.lookup()(), and calling 
the utility would make no sense.

The implementations are the same, but the semantics are quite different. :)



Zope-Dev maillist  -
**  No cross posts or HTML encoding!  **
(Related lists - )

Reply via email to