[Zope3-dev] Context and Component Lookup

Jim Fulton jim at zope.com
Wed Aug 6 18:23:47 EDT 2003


Phillip J. Eby wrote:
> 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,

That's what we're discussing.

 > just as a component that is "part of" a radio would expect to
 > receive its "power" utility from the radio it is composed of.

If I borrow my neighbor's DVD movie,
I'll play it with my DVD player and radio, even though it's still
their DVD. :)


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

Maybe the difference is that my components are connected soley
through interfaces. Your connections tend to be more intimate.

Generally, the dependencies are on interfaces that must be provided in
either case. So I don't see anything "reckless" here.


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

We're talking about sharing content components.  So we get a bit of content
from S2 that we want to use in S1.  We may need to adapt it to something else
we need. I see no harm in using our adapters.


 > It seems like an invitation to debugging hell to
> have things controlled by some kind of threaded global.

And I've experienced debugging hell because objects didn't have the
context I expected them to have.  With what I propose, the source
of components is much easier to predict that the way things are now.



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

Well, I might have a component for converting between formats.  The two sites
might have different components.  I want to use the converter for the site
I'm using the object in.  Also, I'm moving in the direction of unifying many
of the component types.  For example, a view is just a named adapter from
an object and a request to some Often empty) interface.

I can think of a pretty comelling example that supports your point of view,
however. If I modify an object from S2 in S1, I probably want the events to go
to S2.  Then again, it's likely that S1 and S2 will share a common event service,
so it won't matter.


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

We need a basic for looking up components.  If the component's place is the
basis for looking up other components and the component doesn't have a place, then
that's a problem.  OTOH, if we always look up components based on the place we
initiate the computation, we have an unambiguous place to do the lookup.

...

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

You have some presentation code that calls an operation on a content component.
This operation calls other operations, possibly on subobjects or objects
returned from other operations.

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

This is getting circular.  I don't want an object to need to be context
aware to find components. A component should be context aware if *it*
uses context itself in some way, as sometimes happens.  If component lookup
requires context, then any content component that might lookup components
must be context aware.  That's why I don't want component lookup to require
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"? 

If component lookup requires context and if a component wants to do component
lookup, then it must be context aware. It must have the context awareness DNA.
I don't want to require this DNA and, thus, I don't want to require context for
component lookup.

...

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

Adapters *are* proxies.  The proxies I'm refering to are also persistent,
which is usually not the case for adapters.


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

If component lookup requires context, then context awareness is required to
do component lookup.


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

I'm not sure what you just said.  I have components, typically content
components, for which I may need to look up adapters, and other components.
I can't control whether these components for which I need other components
have context.



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

Yes, that's a way to look at it.


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

That doesn't tell me anything. What's self? What't to assure that
self has a context?

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

I'm sorry, I've read this about 5 times and it doesn't make any sense
to me.


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

You are assuming that the caller is aware of context in the first place.
I want to avoid requiring that.

> 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

No, an object need to look up a utility. For it's own use.
Now, it calls getUtility(self, IFoo).

Now suppose that the object isn't context aware. If that's the case,
it will get a global utility.

Finally, assume that all of this happened in a method of an object that
was being used in some site that has an applicable utility, but the site's
utility isn't used.  This is liklely to be surprising to someone.

Perhaps there isn't a global utility, in which case the call fails even though
there is a matching utility in the callers's site.

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

Well, lets consider some possibilities.

Let's suppose A calls getAdapter(B, IFoo, context=A).
Imagine A is from S1 and B is from S2.  Now we'll adapt
B using an adapter from S1, which won't make you happy.

Or, perhaps A doesn't have context information, in which case
we'll either get the global adapter, or we'll fail. At that point,
probably no one's happy.

Now suppose instead, A calls getAdapter(B, IFoo). If B has no
context, then either we'll get a global adapter or fail. Again,
no one happy.

If B does have context, we'll get the adapter from B's context.
At that point, you'll be happy, but I probably won't be.


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

Do you mean that A is presentation code?

But what happens if A calls non presentation code? Should the rules
change?


  or b) it's not presentation-related, and
> object A should use itself (not object B) as the context for adaptation.

So, suppose that we have a view in site S1. Any object it accesses
should be adapted by adapters from site S1.

If the view accesses an operation on a context aware object from S1 and that
operation adapts an object from S2, then an adapter from S1 should be used.

If the view accesses an operation on a context aware object from S2 and that
operation adapts an object from S2, then an adapter from S2 should be used.

If the view accesses an operation on a context aware object from S2 and that
operation adapts an object from S1, then an adapter from S2 should be used.

If the view accesses an operation on a non context aware object and that
operation adapts an object from S1 or S2, then a global adapter should be used.

This all seems pretty arbitrary and likely to lead to debugging hell.


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

Why must we expect an object to supply a context for something?
Generally, the thing supplying context is traversal.
We get objects lots of other ways. When a method returns a value, most of
the time, all it cares about providing is the value itself. It doesn't
*care* what you do with it.  Some methods provide context for their return
values. Where this is done, however, it's to supply context for
context-aware objects that use context for something else.


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

I don't think transparency has anything to do with this.  However,
I think I may be getting a glimmer of what you're suggesting.

I suppose you'd want the context to determine the policy for how to look
up a component. So, for example, the implementation of getService might look
something like:

   def getService(context, servicename):
       sm = getAdapter(context, IServiceManager)
       return sm.getService(servicename)

so that the context could determine the policy for looking up components.
Of course, there's a recursion problem here. The adapter would need to be
provided globally, via __conform__ or via having the context *be* an
IServiceManager already.

Is this the kind of thing you're talking about?

Even with this flexability, I'm not sure how you'd use it. :)

Jim

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




More information about the Zope3-dev mailing list