[Zope-dev] implementing zope.component 4.0

Marius Gedminas marius at gedmin.as
Fri Nov 27 07:11:17 EST 2009

On Fri, Nov 27, 2009 at 12:32:52PM +0100, Martijn Faassen wrote:
> 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.

+0.5 --- I can live with it.  Backwards incompatibility with IFoo(one,
default) will be a slight inconvenience.  There were proposals I liked
more (IFoo.adapt(), IFoo.utility()) and proposals I liked less
(IFoo((one, two, we_like_parentheses, and_screw_people_adapting_tuples))).

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


I've often had the need to "give me an instance that implements IFoo"
where that instance is not a singleton.  I can write the code to find
the right IFoo, but since utilities are so limited, I had to resort to
adapting None.

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

Personally, I prefer Zope's syntax ("decorators" inside the class block)
to Python's (decorators above the class block), aesthetically.

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

Can't be done.

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


from zope.__future__ import new_adapter_lookup?

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

Whoa, great minds think alike ;)

> Is that implementable at all however?

I think so, with some caveats.  E.g. something like

    class Interface(...):

        def __call__(...):
            new_semantics = (sys._getframe(1).f_globals.get('__new_lookup__')
                             is zope.component.__future__.__new_lookup__)

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

Which is why I'd maybe slightly prefer IFoo.adapt(foo, bar) as the explicit
syntax for multiadaptation.  Or live with the status quo.

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

IFoo(one, default), IFoo.adapt(one, two, default=default),

> Most importantly, any volunteers?

Ah.  Um.  Maybe, but only if I get to choose my preferred syntax, and
am allowed to give up after a couple of days declaring the task too

Marius Gedminas
http://pov.lt/ -- Zope 3 consulting and development
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 191 bytes
Desc: Digital signature
Url : http://mail.zope.org/pipermail/zope-dev/attachments/20091127/98b1aaff/attachment-0001.bin 

More information about the Zope-Dev mailing list