[Zope] specifying namespace stacks in <dtml-with>

Michael Halle halazar@media.mit.edu
Sat, 20 Jan 2001 03:07:53 -0500


I was thinking about something I'd consider a useful addition to the
<dtml-with> tag; I'd like to get other people's opinions, especially
about a couple syntax issues.

Problem: In part because of the combination of the dtml namespace
stack and acquisition, it's often hard to get exactly the name
resolution you want in Zope.  For example, I think it's really useful
to want the following:

   "Call an object, found by acquisition, using its "natural" namespace,
    except include a small number of symbols found in the local namespace.
    When evaluating the local symbols, do so in the local namespace."

Why is this useful?  Because it cuts down on accidental interference
of the local namespace in the evaluation of an object, which
acquisition exacerbates because it multiplies the number of symbols in
the local namespace. I'd even go as far as to say that the above
action is what most people want to do most of the time.

How do you do it?  If you do:

<dtml-with object>
  <dtml-with expr="_.namespace(name1=local_object1, name2=local_object2)">
    <dtml-var object>
  </dtml-with>
</dtml-with>

(or the equivalent using an inner "let" tag instead of "with") you get
the right nesting, but "local_object1" and "local_object2" are
evaluated in "object"'s namespace, not the local one.  I *think* the
only way to do it right (I haven't tried it) is:

</dtml-let ns="_.namespace(name1=local_object1, name2=local_object2)">
  <dtml-with object>
    </dtml-with ns>
      <dtml-var object>
    </dtml-with>
  </dtml-with>
</dtml-let>

That way, you can get a namespace evaluated in the local scope onto
the top of the namespace stack to override the object's symbols.
You've got to go through contortions to swap the order of the
namespace stack without introducing unwanted evaluation side effects.

Yuck!

I think is would be much cooler, and more general, to be able to
specify a namespace stack as a list for <dtml-with>:

<dtml-with "[_.namespace(name1=local_object1, name2=local_object2), object]">
    </dtml-var object>
</dtml-with>

The "with" tag's entire expression would be evaluated in the local
scope, *then* a namespace stack would be constructed, using elements
of a list.  

If you had several objects already, the syntax is even cleaner:

<dtml-with expr="[object1, object2, object3]">
  ...
</dtml-with>

In short, this construct lets you build a well-defined namespace stack
without worrying as much about unwanted scope interaction.  It's even
not that hard to write the implementation, except for a couple
questions.

-- First, the "mapping" attribute to "with" is per-namespace; how do
you specify it for elements of the stack?  (The "only" attribute is
okay, it is specified once per stack.)  It would be limiting to say
that all namespaces pushed onto a stack would need to be all be
mappings or all be objects.

-- Second, is the expression for "with" currently ever a sequence?  If
so, then you'd have to recognize and distinguish between the old and
the new usages.  I don't think there's much of a problem here, although
the "with" tag code does do a little checking about whether its
expression is a tuple.

-- Finally, what's the natural order of the stack?  If you give the argument
"[a, b, c]" to "with", is "a" or "c" on the top of the namespace stack?
I'd probably say "a".

I'd appreciate any ideas/suggestions others may have.  Thanks!


Michael Halle
mhalle@media.mit.edu