[Interface-dev] Re: Interface and Adapter Demo

Christian Robottom Reis kiko at async.com.br
Sun Jun 27 14:48:03 EDT 2004


On Sun, Jun 27, 2004 at 09:12:55AM -0400, Stephan Richter wrote:
> Hi Christian,

Hey Stephan, this was great. I've made some comments below, from the
viewpoint of a complete newbie to z.i:

> I have finished the example we started last night and commented it. Since I 
> thought that other people might find this non-Zope-specific example helpful, 
> I CCed the Zope 3 Dev and Interface Dev mailing lists. 

Maybe this could be added to zope.interfaces as a HUMANS.txt document <wink>.

> For statistical reasons we often want to know the size of a file. However, it
> would be clumsy to implement the size directly in the file object, since the
> size really represents meta-data. Thus we create another interface that
> provides the size of something.

Just an orthogonal thought: is it really *that* clumsy to implement the
size as part of the file object? Or it is more of a design decision that
for certain situations makes sense and for others not?

>   >>> class ISize(zope.interface.Interface):
>   ...
>   ...     def getSize():
>   ...         'Return the size of an object.'
>   ...
> 
> Now we need to implement the file. It is very important that the object states

maybe s/very important/essential/

This was one thing that I didn't take into account initially -- the
registry is designed to work exclusively with Interfaces.

> Next we implement an adapter that can provide the 'ISize' interface given any
> object providing 'IFile'. By convention we use '__used_for__' to specify the
> interface that we expect the adapted object to provide, in our case
> 'IFile'. However, this attribute is not used for anything.

Is the convention to use a tuple if used for more than one Interface, or
would that be a `bad thing'?

> Again by convention, the constructor of an adapter takes one argument, the
> context. The context is an instance of 'File' 

perhaps ... in this case is an instance ...

> to extract the size from. Also by convention the context is stored in an
> attribute 'context' on the adapter. The twisted community refers to the

attribute named 'context' perhaps.

Does it make sense to have adapter-specific names, such as naming the
attribute `file' in this case, given the improved understandability of
the adapter's code, or is the adapter's code usual too short for it to
matter? 

> Now that we have written our adapter, we have to register it with the adapter
> registry, so that it can be looked up when needed. 
>
>   >>> from zope.interface.adapter import AdapterRegistry
>   >>> registry = AdapterRegistry()

s/the adapter registry/an adapter registry/

perhaps, and indicate that we're using a single one here, and that it
needs to be explicitly instantiated?

> Register an adapter that adapts from 'IFile' to 'ISize'. The first argument to
> the registry's 'register()' is a list of original interfaces. In our cause we

s/is a list/method is a list/ perhaps

> have only one original interface. 

I find this section a bit heavy on required concepts. You might want
to use something from this alternative summary:

    The registry keeps a map of what adapters implement an interface on
    behalf of other interfaces. To register FileSize, an adapter that
    adapts IFile-providing instances to the ISize interface, we use the
    register() method::

        >>> registry.register([IFile], ISize, '', FileSize)

    The first argument is a list of original interfaces; in our case,
    FileSize only adapts instances providing one interface, IFile.

    Using a list makes sense when the same adapter is available for
    multiple interfaces -- in our case, it might make sense to adapt
    other `sizeable' objects, such as IString and even IDistance.

    The second argument is the interface the adapter provides, in our
    case 'ISize'. 

    [...]

> The third argument in the name of the adapter. Since we do not care
> about names, we simply leave it as an empty string. 

Conventionally (perhaps Zope-conventionally <wink>), what are these
names useful for?

> us to get an adapter instance by simply calling 'ISize(file)'. To make use of
> this functionality, we have to register our registry with some hook mechanism.

Magical, magical adapter_hooks. It took me a while to realize that there
was something else I needed to do to get interfaces to use the registry
to determine how to adapt a certain instance. In hindsight, that makes
sense: you might have multiple registries, registries used in certain
situations and others in others, but it's completely non-obvious at
first sight.

    .. we need to add our registry to the adapter_hooks list, which is a
    member of the adapters module. This list stores a collection of
    callables that are automatically invoked when IFoo(obj) is called;
    their purpose is to locate adapters that implement an interface for
    a certain context instance. 

perhaps.

If we *must* write our own adapter hooks, then it should say so
somewhere; since here is as good a place as any, I suggest:

    You are required to implement your own adapter hook; this example
    covers one of the simplest hooks that use the registry, but you
    could implement one that used an adapter cache or persistent
    adapters, for instance.

>   >>> size = ISize(file)
>   >>> size.getSize()
>   7
> 
> That's it. I have intentionally left out a discussion of named adapters and
> multi-adapters, since this text is intended as a practical and simple
> introduction to Zope 3 interfaces and adapters. You might want to read the
> 'adapter.txt' in the 'zope.interface' package for a more formal, referencial
> and complete treatment of the package.

Note that adapter.txt makes my brain feel soft (and someone else has
said the same thing to me -- though perhaps just to make me feel
better). It seems to be at points trying (and succeeding <wink>) *on
purpose* to confuse me, via the use of integers (what is 12?) in place
of "context".  This is actually compounded by the adapt_0_to_42 adapter
hook exemplified in interface.py -- I was almost sure adapter_hooks were
what I wanted but the example just didn't make sense -- it doesn't even
use the iface argument, and nowhere does it suggest I might want to use
the registry.

It would help tons just to add the simplest adapter hook that used the
registry as an example, and point to it -- many people will need
something more specific, but there's at least something to start from.

Thanks a lot for taking the time to write this.

Take care,
--
Christian Robottom Reis | http://async.com.br/~kiko/ | [+55 16] 3361 2331


More information about the Interface-dev mailing list