[Zope3-dev] Context and Component Lookup

Phillip J. Eby pje@telecommunity.com
Wed Aug 6 20:22:54 EDT 2003


At 02:27 PM 8/6/03 -0400, Jim Fulton wrote:
>Phillip J. Eby wrote:
>>At 12:11 PM 8/6/03 -0400, Jim Fulton wrote:
>>
>>>>Conversely, for anything that's not presentation-based, shouldn't a 
>>>>component use its containment context for lookups?
>>>
>>>
>>>That's the question.  I'm suggesting that components should use a
>>>context that's decided by the application.
>>
>>Ah.  Okay, if we're talking about non-presentation components -- and 
>>assuming I understand this correctly -- then I strongly disagree, on the 
>>grounds that it makes it difficult for a developer to reason about the 
>>behavior of a component,
>
>Why? I submit that it is easier to reason about, because there is only
>one site that contributes components.
>
>(FWIW, I can see your point and have some sympathy for your point of
>  view.)

As I implied, it's possible I'm completely missing what you're talking 
about, and am being fooled by a merely superficial resemblance to the 
problems I've been working on that led me to my conclusions.  :)  Now that 
the disclaimer's out of the way, let me explain what I mean.

I assume that component lookup context should be based on a *composition* 
relationship.  If a content component is "part of" a site, then it is 
reasonable to assume that utilities should "come from" the site, just as a 
component that is "part of" a radio would expect to receive its "power" 
utility from the radio it is composed of.



> > and too easy for one application context to
>>"pollute" another and break intended invariants.
>
>That can happen in either case. If I use an object from another
>site with it's components, those components might break my invariants,
>or my site might not provide an adequate environment for them.

Maybe I'm misunderstanding what you mean by "use".  I can think of two 
kinds of use:

1) Present a foreign component, using local presentation rules
2) Invoke non-presentation operations upon a foreign component

#1 obviously requires that I control where presentation adaptation is done, 
but that's okay because the foreign component doesn't need to know anything 
about that.  For #2, it seems downright reckless for me to try to do some 
kind of hidden parameterization by changing the foreign component's 
operating environment while I'm calling it.  If I need to parameterize the 
component, why not just make an instance of it that's attached to my 
environment, or else explicitly define parameters as part of the call 
signature?  It seems like an invitation to debugging hell to have things 
controlled by some kind of threaded global.


>I should point out that I'm less concerned with sharing of objects
>across unrelated sites. That just seemed like a simpler example.
>A more realistic example is one where I have say site S1 and site S11,
>such that site S11 is contained in site S1.  If I'm in S11 and I use
>an object from S1, I'd like to use components defined in S11, if,
>and the other way around.
>
> > A content object
>>should have one and only one "place".
>
>It does. I'm not convinced that that should be the sole basis for finding
>components, especially given that many objects don't have a place.

But do you have any other use cases, besides presentation?  I don't.  But 
maybe there is something we don't agree on regarding what it means to "use" 
a component?


>Sure. That's just an example. The point is that there are many components
>that don't have containment information, many of which don't really have
>a place.

But why do they need one?


>>>Similarly,
>>>components may be computed and returned from a method. These also are
>>>effectively placeless. Even values that are stored might not get a 
>>>containment
>>>context because the objects that store them don't bother to set a context.
>>
>>So adapt them to a context interface, and "suggest" to them a parent 
>>component.
>
>If the object is a method return value we have no place to suggest.
>
>
> > This can be done in the presentation-level code, similar to
>>how you do context wrappers now.
>
>No, because the component lookup may be far removed from the
>presentation code.

*confused look*.  I think I really need a real (i.e. motivating) use case 
to understand this.


> > I mean, you're presumably going to
>>have an 'IContainerAware' or some such, right?
>
>Sure, but most objects won't implement it.  I don't want to *make*
>objects implement it soley to use the component architecture.
>
>Objects that don't implement it will in some cases (e.g. when they
>are added as an item of a container) have proxies put around them to
>provide them with the information, but methods of the proxied objects
>won't have access to the proxy.

Why would they need it?  If they *need* to have context, shouldn't they be 
context-aware?



> > You just need a way to
>>"suggest" to such an object what its containment is, if it doesn't 
>>already know, and have an adapter that can adapt anything to that 
>>interface.  And, the adapter needs a __conform__ that adapts the thing it 
>>wraps.  Now, you can convert the container-awareness adapter back to any 
>>other interface you're looking for.
>
>This just isn't practical. I speak from experience.  For an object to
>use context, it needs special DNA, which is OK,

I grok this sentence so far.... (presuming you mean "for an object to use 
*its* context")


>  but I'm not comfortable
>requiring special DNA to work with components.

...and then I don't get this.  What are you saying is the "special DNA" to 
"work with components"?  Are you saying that you think all objects involved 
in a containment chain would need to be context-aware?  Are you saying you 
think an object using the CA would have to be context aware, itself?

(For that matter, I don't see why you think *proxies* are necessary for 
objects to have context.  Adapters are quite sufficient; for example in 
PEAK I have an adapter for ModuleType so that modules can be considered 
components which have their package as their context.)


>>Of course, such unaware objects can't *themselves* look anything up by 
>>their context...  But why on earth would they need or want to?
> > I mean,  if the object needed to do lookups in its context, wouldn't it 
> mix in
>>some awareness?
>
>I agree, but should context awareness be a prerequisite for working with
>the component model? I suggest not.

I guess I'm confused on why you think this is required.


> > Conversely, as long as your traversal mechanism adapts
>>objects to container awareness, and "suggests" to them where they were 
>>retrieved from, then an aware object will "imprint" on the first context 
>>it's used in.
>
>That works great to the extent that we get to objects via traversal, but
>traversal isn't the only way to get to objects. We often get to objects
>via method calls. We have been forced in many cases to make the methods
>wrap their results.  This is a lot of bother.  It significantly slows
>development.

*lightbulb goes on, briefly*  I think *maybe* I understand what you're 
saying, but let me see if I can paraphrase it:

1. You need to look up components in the context of some other component, 
either utilities, adapters, or "other".

2. Because components cannot be generally assumed to be context aware, 
*all* code ends up assuming a burden of supplying context to the objects 
that are being passed around.

I think I've managed to avoid this problem in two ways...  first, I almost 
never look up utilities in the context of another object than 
self.  Instead, the responsibility for providing the utility is placed on 
the interface of the object that would be the context for such a 
lookup.  That is, utilities should be part of an explicit interface, or the 
use of them hidden within their client.  (The supplying component may then 
look up the utility in its own context, but the point is that it's the 
supplier's responsibility.)

Second, for adaptation, the caller is always in effect required to know the 
context for adaptation, because it is the caller's context that desires the 
functionality.

Now, it may be that these approaches can't work for Zope 3 for some reason; 
maybe there is a lot more need for objects to poke into each others' 
business that I'm not understanding.  If somebody can point me at some code 
that they don't believe this approach works for, it would help my 
understanding tremendously.

Specifically, a counterexample would be a situation where either:

1. An object A looks up a utility in context of object B, but it does not 
make sense to explicitly require IofB to provide the utility as an 
attribute or via a method, or

2. An object A gets an adapter (or view) of an object B, and it does not 
make sense for A to use itself, or some known context-aware collaborator, 
as the context for the adapter/view lookup.

In my understanding, it seems that #2 would almost always be resolvable to 
either a) it's a presentation-related adaptation/view, and belongs in a 
context based on the request, or b) it's not presentation-related, and 
object A should use itself (not object B) as the context for adaptation.


>Worse, developers usually don't understand why it's necessary.
>Something doesn't work, so they look into their book of incantations.  The
>book suggests that maybe a context wrapper will work, so they offer one up.
>To them, it's a dead chicken.

I think that will be helped a lot by making it explicit, and *not* a 
"transparent" wrapper.  If an object is expected to supply a context for 
something, it really should be explicit *what* you're going to look up in 
that context as well, so that the supplier will know whether they care what 
you get.  Thus, the supplier can also *control* it, by explicitly giving 
you a context that will produce the results they desire.  As long as all 
this stuff is implicit, it's not controllable.





More information about the Zope3-dev mailing list