[Zope-Perl] Re: Method binding

Michel Pelletier michel@digicool.com
Wed, 18 Oct 2000 12:14:12 -0700


Jim Fulton wrote:
> 
> Michel,
> 
> You have advocated that methods should always be bound to the objects they
> are accessed in. You argue that there should be no choice in the matter.

I advocate more points than that, like being able to document python
with python, no XML mixed in with a language, Py Meths working like
other methods do, but yes that is one of them.  

My argument should be more flexible in regard to choice, a willing
compromize is to switch the default binding of context and container,
making 'self' the default for context and something else the default for
container.

> I have to disagree strongly. I'll try to explain why.
> 
> In Python, methods are bound to instances.  Methods are part
> of an instance's core behavior. They are specific to the kind
> of thing the instance is. In my words, methods are part of
> the genetic makeup of an object.

Python methods are meant for through the web usability and programming
ala the existing Zope model.  90% of your audience just scratched their
heads.
 
> In Zope, we allow some methods to be bound to their context.
> This is done in a number of ways and is sometimes very useful.
> We have methods, like standard_html_header, which are designed
> to be used in different contexts.

this is how I feel python methods should be designed to be used.
 
> We have other methods, like manage_edit that are designed to
> work on specific instances. It would be an egregious error
> if this method was acquired and applied to it's context.

I think this is a weak argument, none of the built in Zope methods mean
anything to the average user, they can't find them, click on them, edit
them, or copy them to their own method to change and experiment with.  
 
> We have some methods that are designed to bound to an instance
> (container, in your terminology)

Python Method terminology

> but that, because they are written in
> DTML, can be bound to other objects. This can cause significant problems.
> For example, methods defined in ZClasses almost always want to be
> bound to ZClass instances, not to other arbitrary objects.
> 
> <aside>There's a bonus problem with DTML Methods. When
> a DTML Method is invoked from another DTML Method, it
> is bound to neither the object it was accessed in or
> to the object it came from. It is bound to the calling
> namespace. It turns out that this is a useful behavior
> if the DTML Method is designed to be used as a "subtemplate".
> </aside>

This is because DTML binding is implicit, not because it's backward. 
This problem doesn't effect python methods because you allways bind a
method in python when you call it.  The question is how the initial
method gets bound.
 
> There is no one "right" way to bind a method. There are good
> reasons to sometimes bind a method to it's context and
> sometimes bind a method to it's container (ie instance).
> There are even sometimes reasons to bind a method to a
> calling namespace.
> 
> The principle of least surprise doesn't help here, because
> methods defined in Python classes don't behave the way
> methods defined through the web do currently.
> 
> We *need* control over binding, as well as reasonable defaults.
>
> If we can agree that we need binding control, the question
> arises as to some details and default names.

I agree there must be control over binding, although your arguments
above have not convinced me that Python Methods are doing it the right
way, actually, it's convinced more than my argument, compromisingly of
course, is more right.
 
> Should it be possible to do more than one binding at a time,
> using multiple names?  If not, then I'd agree that the name
> 'self' should be used for either the context or container binding.

I'm with you so far with that.

> If both bindings are allowed at the same time, then 'self' should
> refer to container binding to be consistent with standard Python
> usage and some name like 'context' should be used (by default)
> for contextual binding.

That's what I disagree with.  I don't think you've given a strong
corollary to standard python usage.  The only strong argument you've
given so far is the ZClass one, but 10 gives you 1 that's not the
primary use case (it may be the one in Fburg).  People are going to be
defining these methods in Zope to make their lives easier, probably bad
design and mad hacks and no structure, but that's how 90% of the world
gets their work done and easing that burden is the usability task.  You
have not convinced me that:

1. Something called a Python Method should not resemble a method
definition in python.

2. Something called a Method in Zope should not behave like the other
Methods (meaning through the web objects) in Zope

3. Common, *documented* well understood URL manipulations (context) are
less important than (the less common) containment oriented design and
ZClasses.

Consider the following passage in the documentation:

      For example suppose you want to call a method named *viewFolder*
on
      one of your folders. Perhaps you have many different *viewFolder*
      methods in different locations.  Zope figures out which one you
want
      by first looking in the folder that you are calling the method on.
If
      it can't find the method there it goes up one level and looks in
the
      folder's containing folder. If the method can't be found there it
      goes up another level. This process continues until Zope finds the
      method or gets to the root folder. If Zope can't find the method
in
      the root it gives up and raises and exception.

and:

      Zope breaks the parts of the path up and walks along the object
      hierarchy looking for each part. This process is called *URL
      traversal*. For example, when you give Zope the URL
      *Zoo/LargeAnimals/hippo/feed'*. It starts at the root folder and
      looks for an object named *Zoo*. It then moves to the *Zoo*
      folder and looks for an object named *LargeAnimals*. It moves to
      the *LargeObjects* folder and looks for an object named
      *hippo*. It moves to the *hippo* object and looks for an object
      named *feed*. The *feed* method is found in the *Zoo* folder by
      a process called *acquisition*. Now Zope has reached the end of
      the URL. It calls the last object found, *feed*, on the second
      to last object found, the *hippo* object. This is how the *feed*
      method is bound to the *hippo* object.

And further on:

    Suppose 'feedHippo.py' is a Python Method. How could you call the
    'Diet/feed' method on the 'LargAnimals/Hippo' object from your
    Python Method. Here's how::

      self.Zoo.Diet.LargeAnimals.hippo.feed()

    In other words you simply access the object using the same
    acquisition path as you would use if calling it from the
    web. Likewise in Perl you could say::

      $self.Zoo.Diet.LargAnimals.hippo->feed();

    Using methods from other methods is very similar to calling
    methods from the web. The semantics differ slightly but the same
    acquisition rules apply.

These paragraphs are just exceperts from two whole sections that try to,
quite sucessfully acording to the feedback we've gotten, explain the
method binding pattern in Zope.  We give a real world application and
justification in both sections on why this is useful and explain the
concept in simple terms.  Now, this needs to be re-explained, rewritten,
and made overly complicated for what I feels are not very important
reasons.  Where are the applications and design patterns documented for
your argument?  Perhaps those could convince me if they justified it
from the perspective of the beginner.  I suggest you read over Chapter 7
and weigh these descision from the eyes of a newbie.

-Michel