[Zope-dev] implementing zope.component 4.0
Martijn Faassen
faassen at startifact.com
Fri Nov 27 06:32:52 EST 2009
Hi there,
Introduction
------------
So now that we've had some discussion and to exit the "bikeshed" phase,
let's see about getting some volunteers to work on this.
The goal here is to make interfaces disappear into the language as much
as possible. This means that I'll ignore backwards compatibility while
sketching out the "ideal semantics" below - I have the impression we can
get consensus on the following behavior:
Simple adaptation:
IFoo(adapted)
Named adaptation:
IFoo(adapted, name="foo")
Adaptation with a default
IFoo(adapted, default=bar)
Multi-adaptation:
IFoo(one, two)
Named multi adaptation:
IFoo(one, two, name="foo")
Multi-adaptation with a default:
IFoo(one, two, default=bar)
Utility lookup:
IFoo()
Named utility lookup:
IFoo(name="foo")
Utility lookup with a default:
IFoo(default=bar)
Where "name" and "default" can be combined. The name and default keyword
parameters have to be used explicitly - *args is interpreted as what to
adapt only. Any other keyword parameters should be rejected.
Utility lookups versus adapter lookups
--------------------------------------
There was some discussion on whether utility lookups are really
something fundamentally different than adaptation as adaptation
*creates* a new instance while utility lookup uses a registered
instance. I think the essential part here is however: "give me an
instance that implements IFoo", and utility lookup fits there. We could
even envision a way to create utilities that *does* instantiate them on
the fly - it shouldn't affect the semantics for the user of the utility.
Features off the table for now
-------------------------------
Saying an interface is implemented by a class (Python 2.6 and up) with a
decorator we'll leave out of the discussion for now.
It would also be come up with an improved API to look up the adapter
*before* it is called, but I'd also like to take this off the table for
this discussion.
Backwards compatibility
-----------------------
Now let's get back to my favorite topic in this discussion: backwards
compatibility. The ideal semantics unfortunately break backwards
compatibility for the single adapter lookup case, as this supports a
second argument, the default.
The challenge is therefore to come up with a way to support the new
semantics without breaking the old.
We could introduce the following upgrade pattern:
zope.component 3.8.0: old semantics
zope.component 3.9: old semantics is the default. new semantics
supported too somehow but explicitly triggered.
zope.component 4.0: new semantics is the default. Old semantics is not
supported anymore.
We could, if needed, maintain zope.component 3.x in parallel with the
new-semantics 4.0 line for a while.
A per-module triggering of the new semantics might be done like this:
from zope.component.__future__ import __new_lookup__
Is that implementable at all however? Someone needs to experiment.
Alternatively we could do something special when we see this: IFoo(foo,
bar). This is ambiguous - is the new semantics in use or the old one? If
the adapter cannot be looked up using multi adaptation we *could* fall
back on single adaptation under the assumption that the old semantics
are desired. But this will lead to a problem if the new semantics *was*
desired but the component simply could not be found.
I think it's important not to do a "big bang" upgrade but instead allow
people to upgrade bit by bit. It should be possible to compose an
application that mixes code that expects the old semantics with code
that expects the new semantics. A bit by bit upgrade I think would
ideally be on a per-module basis. I think it's important to make sure we
can support such an upgrade *before* we release any of this.
Conclusions
-----------
Are people okay with the proposed semantics?
Would people be okay with such an upgrade path? Any better ideas?
Most importantly, any volunteers?
Regards,
Martijn
More information about the Zope-Dev
mailing list