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 case? 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? [snip] > 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 IFoo(a) * 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 IFoo.lookup(a)(a) 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. :) Regards, Martijn _______________________________________________ Zope-Dev maillist - Zope-Dev@zope.org https://mail.zope.org/mailman/listinfo/zope-dev ** No cross posts or HTML encoding! ** (Related lists - https://mail.zope.org/mailman/listinfo/zope-announce https://mail.zope.org/mailman/listinfo/zope )