[Zope-dev] implementing zope.component 4.0

Martin Aspeli optilude+lists at gmail.com
Sun Nov 29 10:14:16 EST 2009


Martijn Faassen wrote:

> Multi-adaptation:
> 
>    IFoo(one, two)

Please note that this will break an incredible amount of code "in the 
wild". A good number of my packages do something like this:

   foo = IFoo(context, None)
   if foo is None:
      ...

There is a lot of documentation out there (including at least three 
books in print) encouraging this pattern, too. How is someone reading an 
"old" document supposed to know what's going on when the semantics of 
this call suddenly changes radically?

I love all the other suggestions. In my book, this one would be an 
incompatibility too far, though. I think the version of passing a tuple 
would be a better compromise, not at least because there's only a very 
small number of people who will've attempted to single-adapt a tuple (or 
a tuple sub-class).

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

+1

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

Agreed, but we should tackle those in a separate proposal.

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

-1

Because we now have so many packages and things are being released as 
eggs and mixed up in various platforms and projects, this type of 
"gross" backwards incompatibility is virtually impossible to manage.

To take an example, I'm sure Stefan & co will release z3c.form 3 
depending on zope.component 4 before long, and we'll want to use that in 
Plone. Except we can't, because even if z3c.form never uses the 
IFoo(one, two) syntax, everything in Plone that uses IFoo(context, None) 
would suddenly break.

I'm sorry, but I think the ship on "perfect API" has sailed. We have to 
own up to our past decisions and compromise, at least on the patterns 
that are widely used, and where there is almost certain confusion and 
failure.

I think Jim said once, "we can't ever have backwards incompatibility". 
Other "serious" platforms like Java or .NET have a similar stance. They 
deprecate liberally, but never actually break anything. (Remember 
java.util.Data and java.util.Calendar?) We may never be able to do that 
completely, and we may *want* to root out some dodgy bits of code that 
few people use. But breaking something so fundamental and so commonly 
used would be criminal, in my book.

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

This is probably the minimum I'd be prepared to accept, personally. It's 
ugly and risky still, but at least it'll cover the 90% use case. I still 
don't like it, though.

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

I'm not sure that's going to be possible. As soon as someone does 
zope.component >= 4.0 in their setup.py, you're screwed.


> Conclusions
> -----------
> 
> Are people okay with the proposed semantics?

Apart from the second argument thing, I love them. :)

> Would people be okay with such an upgrade path? Any better ideas?

No. I'd say we need to maintain backwards compatibility forever. This is 
*such* a fundamental part of our ecosystem that anything less is to make 
a mockery of ourselves.

> Most importantly, any volunteers?

Sorry, probably not me. ;-)

Martin


-- 
Author of `Professional Plone Development`, a book for developers who
want to work with Plone. See http://martinaspeli.net/plone-book



More information about the Zope-Dev mailing list