[Interface-dev] Doing multi-adaptation through interface call (again)

Jim Fulton jim at zope.com
Sat Aug 14 08:16:42 EDT 2004


I really like being able to do adaptation by calling
interfaces.  Zope uses multi-adapters a fair bit.  These are
adapters that adapt multiple objects.  They have a number of
differences from single adapters:

- The adapt multiple objects.  The factories have multiple arguments.

- __conform__ isn't used

- There's no question of whether an object already implements an
   interface.

As mentioned here before, I'd like to be able to use tuples to
indicate multi-adaptation in Zope:

   adapter = IFoo((a, b))

This is potentially a problem, because someone might have registered
an adapter for tuple.

I'd like to suggest the following compromise:

   Zope's component facility will register an adapter hook after
   the normal adapter hooks.  This hook will, if a tuple if given,
   try to get a multi-adapter.  If someone has registered a normal
   adapter from tuple, then that would be found first by the normal
   adapter hooks and take precedence over any multi-adapters.

With this mechanism, multi-adapters can be supported without affecting
regular tuple adapters. In the unlikely event that there are both
tuple adapters and multi-adapters providing the same interface, the
multi adapters will lose.

Some alternatives (think of the above as alternative A):

B. Allow multiple arguments to __call__, as in:

      adapter = IFoo(a, b)

    This introduces 2 ambiguities:

    1. In a two argument case, we can't distinguish multi-adaptation
       from single adaptation with a default.  We could fix this by
       always requiring that the default be given as a keyword argument,
       but that introduces a backward incompatability.

    2. In a single-argument case, we can't distinguish the normal-adapter
       case from the multi-adapter (with one input) case.  One could argue that
       this is a yagni, but I'm a bit uncomfortable saying that multiple
       adaptation is for 0, 2, or more than 2 objects.

C. Add additional methods to interfaces.  I wanted to avoid cluttering
    the interface API with to much component support, however:

    - Adaptation is a pretty important feature of interfaces, and

    - Zope's component architecture is coalescing to the point where it consists
      solely of adapters and utilities, where, clearly, adapters are the most important.

    - The adapter registry is provided by the interface package, so, perhaps
      it makes sense to surface access to registries in the interface API.

    If we did this, I'd probably add the following interface methods:

       def multi_adapt(*objects, **options):
           """Adapt multiple objects

           Options:

           - default: The value to return if no adapter can be found. This
                      defaults to None

           - name: Look up a named adapter with the given name.
	  """

       def subscribers(*objects):
           """Return the subscribers for the given objects

	  An iterable object is returned.  Adapters are not computed until
           they are returned by the iterator.  So, for example, if you had a for loop
           like:

                for subscriber in IFoo.subscribers(a, b):
                    if some condition:
                       break

           Then subscribers not yet retrieved when we break out of the loop are
           not computed.
           """

    This is slippery slope. I can also think of a number of other methods to handle
    more obscure cases that are needed in Zope, but not often.


Thoughts?

Jim

-- 
Jim Fulton           mailto:jim at zope.com       Python Powered!
CTO                  (540) 361-1714            http://www.python.org
Zope Corporation     http://www.zope.com       http://www.zope.org




More information about the Interface-dev mailing list