[Zope-dev] summary of discussion was: adapter vs factory Re: implementing zope.component 4.0
Chris McDonough
chrism at plope.com
Tue Dec 1 12:27:23 EST 2009
Martijn Faassen wrote:
> Chris McDonough wrote:
>> Personally I think that it's a fantasy to believe that the difference between
>> an object created via a factory on-demand and an object simply returned should
>> *never* matter to a caller. You may not want the caller to need to care, and
>> it may be inconvenient to take into account circumstances where the caller
>> needs to care. But because this is Python, the caller still often does need to
>> care.
>
>> The only circumstance where a caller would *never* need to care would be when
>> the object returned could be guaranteed to *never ever* have any methods called
>> on it that weren't part of the interface defined by the interface being looked
>> up. If we want this, we should probably just be using Java.
>
> I think it's okay for us to say: if you call a method on something that
> you retrieved by interface that isn't actually specified to be on that
> interface, you're on your own. It may work, but it's not specified to
> work by the system you're using.
Let's use an analogy here.
You are a member of a club. This club is very inclusive, but it has a fairly
rigid set of protocols that members are expected to follow. For example, when
you enter the front door, you are expected to touch a statue next the the door.
When a bell rings, you are expected to sing the club song. At precisely 1pm,
everyone must kneel in place. A number of other arbitrary actions are required
of a new member, and new ones are added every so often.
This club is slightly superstitious, so it is believed that *not* performing
the required actions is bad luck, and any member who does not perform them "to
the letter" will bring a pox upon the club and all its other members. In fact,
the club members have incontrovertable evidence that this is so.
The club currently has a membership in the hundreds. They want to be
inclusive, so they welcome anybody, and they're glad to get new members. But
those who come in are expected to read a slightly tattered printout of a
PowerPoint presentation hanging from a string on the inside of the front door.
This printout contains all the known actions that a member must perform in
response to cues to be a member in good standing. New members can also ask
existing members for help, of course, and they can go visit the printout any time.
If everyone follows the set of instructions in the powerpoint document to the
letter, everything runs swimmingly. But the powerpoint document is missing
some pages, (some new cues were added recently) and even if it wasn't, new
members would almost always have a hard time getting it *all* right on the
first try because there are a lot of cues these days. The bell rings, they
kneel. They sing the song at the wrong time. Sometimes they just don't know
what to do, so they do nothing.
The club also has a wait staff. Currently the wait staff is not expected to
enforce any of the rules; they simply keep things running. They are severely
underworked at the moment.
Currently the club interpersonals are a little broken: when a new member has
the wrong response to a cue, the existing club members might try to help that
new member, but often they just complain to each other about the offending new
member. Some members just claim "I've already paid my dues to be a member
here, he should too." Other members try to write more little sticky notes and
hang them up as cues to new members, but nobody is really "responsible" for
teaching new members the rules. It's sink or swim, and often new members sink.
If the the "club" is the "ZCA community", the "cues" are the worldview that
says that the ZCA is by god a way to convert one interface to another and that
utility and adapter lookups are no different than each other, the wait staff is
the ZCA itself, new members are new developers, and the mistakes they make when
not following the cues using methods of the adapted objects that aren't defined
by the adapter interface:
1) Put the wait staff in charge of helping new members. This is analogous
to making the ZCA throw (or at least warn) about errors that new developers
make by using attributes and methods of an object not defined by the
interface returned by an adapter or utility lookup.
2) Get rid of most of the cues. This is analogous to "unifying" adapter lookup
and utility lookup by making the *caller* responsible for doing "adaptation"
by calling the result of the lookup himself.
Or do nothing. Doing nothing is wrong because at some point *we* become
maintainers of code written by folks that "didn't get the jokes" of the ZCA
worldview. So we can either take the joke out or make the joke impossible to miss.
> I'm not sure why lifetime issues are considered so important here. Of
> course they sometimes matter. But we use ORMs all the time. We create
> traversal hierarchies on the fly all the time. What's different in this
> case?
>
> If I want to index an object, do I care whether the catalog was just
> created on the fly and it's talking to a relational database?
>
> I think you're arguing that because abstractions are sometimes leaky
> (lifetime issues) we shouldn't have this abstraction at all. Why is the
> leakiness so important here?
*This* abstraction is leaky. Other ones which have been proposed are not. Or
at least not as.
> I think there are two centers of attraction for unification:
>
> * everything is a factory. If I want to look up an instance, I look up a
> factory that returns me the same instance all the time. I.e. IFoo() and
> IFoo(a)
>
> * everything is an instance. If I want to call a factory, I look up an
> instance that is a factory, and call it. I.e. IFoo.lookup() and
> IFoo.lookup(a)(a)
I think either of these positions is probably consistent.
> zope.component presents a compromise between those positions.
I don't know that the documenting the compromise as a worldview is particularly
useful, given that any reasonable Python programmer can add back the compromise
abstractions with about 10-20 lines of his own code should he want to.
> The advantage I see of unifying towards factories is a less verbose API
> for common operations than an explicit API would have.
>
> If you take the utilities come from a factory approach, this would
> suggest an API like this (on Interface):
>
> def __call__(self, arg=()):
> if not isinstance(arg, tuple):
> arg = (arg,)
> return self.factory(arg)(*arg)
>
> # low level
> def factory(self, arg=()):
> return registry.lookup(from_=arg, to=self)
>
> The drawback is that while you *can* register utilities as non-factories
> and look them up, you'd do it through 'factory', as the real way to look
> up utilities would be to call a factory.
>
> If you take the utilities are registered instances, that would suggest
> an API like this:
>
> # convenience
> def __call__(self, arg=()):
> if not isinstance(arg, tuple):
> arg = (arg,)
> return self.lookup(arg)(*arg)
>
> def lookup(self, arg=()):
> return registry.lookup(from_=arg, to=self)
>
> You'd register utilities as instances directly and look them up using
> lookup(). The convenience method still works for adapters.
>
> The drawback is that IFoo() would result in IFoo.lookup()(), and calling
> the utility would make no sense.
>
> The implementations are the same, but the semantics are quite different. :)
I will try to understand this more later.
- C
>
> Regards,
>
> Martijn
>
> _______________________________________________
> Zope-Dev maillist - Zope-Dev at zope.org
> https://mail.zope.org/mailman/listinfo/zope-dev
> ** No cross posts or HTML encoding! **
> (Related lists -
> https://mail.zope.org/mailman/listinfo/zope-announce
> https://mail.zope.org/mailman/listinfo/zope )
>
More information about the Zope-Dev
mailing list