[Interface-dev] Re: Interface and Adapter Demo [resend]

Philipp von Weitershausen philipp at weitershausen.de
Mon Jun 28 11:50:04 EDT 2004


Christian Robottom Reis wrote:
> 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>.

+1

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

It is not at all clumsy. The idea of the ISize interface is the following:

Imagine you have many different objects, some of them files, some of
them not. But you want to display some sort of size for them. Even if
all of those objects would be able to tell you their size, what would
the API be? obj.getSize(), obj.get_size(), obj.size? We don't know! So,
the idea is to have your size displaying component require a certain
API, which we model in ISize. By adapting objects to *your* ISize, you
rely only on your own API, not the object's.

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

Yes, it is essential. The adapter registry only works 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'?

We haven't made any semantic use of the __used_for__ yet. Right now it
is merely an explicit form of documentation. Like Tres said, it makes
little sense to be adapting several interfaces. If those interfaces have
something in common which is to be adapted, then that should be a
separate interface; if not for the adapter, then for documentation purposes.

We might come up with a formalization of __used_for__ in the future. I
would welcome such a thing for symmetric reasons.

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

The convention is to use context. I think in the long term it'll be
easier when everything reads 'context' wherever adaption takes place
than 'file', 'foo' or even 'i'...

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

Named adapters are used frequently in Zope 3 for views. Views, such as
HTML browser pages, adapt an object together with a request (a browser
request). They are looked up by name:

>>> registry.queryMultiAdapter((object, request),
...                            zope.interface.Interface,
...                            name)

So, in Zope 3, views are actually multi adapters (because two objects
are adapted, the object and the request, with names (e.g. 'index.html')
providing zope.interface.Interface (the most general interface there is).

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

Well, I think it's as least magical as it can get since you have to
provide the hook yourself. The hook doesn't even have to involve an
adapter registry.

Usually, these kinds of things are taken care of during boostrapping of
  the package so that one doesn't have to worry about them anymore.
Subsequent code should simply be able to use ISize(file).

Note that the component architecture (zope.component) provides an
adapter service that automatically hooks itself into the adapter_hooks.
You might want to look at that code; it's easy reading :).

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

I think Stephan's good example, with your clarifying comments, would
make a good "HUMANS.txt" :).

Philipp





More information about the Interface-dev mailing list