On 3/26/02 1:21 AM, "Claude Brisson" <[EMAIL PROTECTED]> wrote:

> 
> I'd like to discuss a strange behaviour (already mentionned sometimes, but
> without any concluding point, imho), and to make a
> proposal.
> 
> When velocimacro.context.localscope is false, a macro may implicitely change
> the actual value of its arguments by changing some
> external variable implied in their calculation.

Yep.

> 
> This is due to the fact that each time a non-constant argument is evaluated in
> a macro, it is re-evaluated with the global context
> that may have been changed by the same macro.

Yep.
 
> For instance, as shown in example 1, if a #foreach or a #set directive inside
> a macro uses a reference name similar to the name of a
> reference passsed to the macro, then the actual value of the parameters may
> also change in the same time.
> 
> ---------------------
> 
> ## Example 1 :
> 
> ## outputs "1 ! a b c" instead of expected "1 1 1 1 1"
> 
> #macro (test $arg)
> $arg ## -> 1
> #set($i = '!')
> $arg ## -> !
> #foreach ($i in ['a','b','c'])
> $arg ## -> a b c
> #end
> #end
> 
> #set($i = 1)
> #test($i) ## outputs "1 ! a b c" instead of expected "1 1 1 1 1"
> 
> ---------------------
> 
> This may be seen as a small side effect, but it can lead to very ankward
> behaviours in some situations... especially when dealing
> with macro recursions.

Yep.

It was hard work to make this behave this way :)

Originally, you could originally imagine that a VM invocation was simply an
inline replacement with it's definition, with the corresponding references
replaced with the passed in args.

When the VM system was redone, that behavior had to be mimiced w/o breaking
things, so there is a 'pass by name' system - where the local reference in
the VM is really like a reference to the outer reference that it was invoked
with.

I say 'pass by name' rather than 'pass by reference' because you can do
weird things like

#macro(foo $colortool)
   <tr bgcolor=$colortool><td>...</td></tr>
   <tr bgcolor=$colortool><td>...</td></tr>
   <tr bgcolor=$colortool><td>...</td></tr>
   <tr bgcolor=$colortool><td>...</td></tr>
#end

#foo( $tool.nextRowColor() )

And the method nextRowColor() will get invoked each time (i.e. 4 times in
the VM 'foo').


> ---------------------
> 
> ## Example 2 : (partial)
> 
> #macro (disp_node $node)
> #foreach ($child in $node.children())
> 
> $child.name is a child of $node.name
> ##                        ^^^^^^^^^^      (I hate proportional fonts)
> ## "$node.name" evaluate to (external) "$child.name", which equals (internal)
> "$child.name"
> ## so for a basic tree (grandparent-parent-grandson) we get the output
> "grandson is a child of grandson"
> 
> #disp_node($child)
> #end
> #end
> 
> ---------------------
> 
> This recursion problem should also be solved if #foreach directives avoided to
> store their working variables in the global context,
> but it's another point.

Indeed :)  That's possible, but it involves some kind of inverse wrapping
such that that val is protected.

Also, someone may expect to look at the last val in the context :

#foreach($item in $items)
...
#end

#if($item == 'whatever')
  Last was 'whatever'
#end


> 
> I finally made it out for my personal stuff, by the mean of two or three
> dreadful workarounds, but here is my point :
> 
>     Why couldn't macro directives only evaluate once their arguments at the
> moment they are called and save them in their local
> context ?
> 
> This sounds too simple... do I miss something ?

The thing we would lose is that method invocation feature, and people may be
expecting that they can use a VM to alter the global context.

Why not make context.localscope true?  What's the problem there?

> 
> As shown in example 3, only vicious minds (like mine here, for a didactic
> purpose) may try to exploit constructively this behaviour.
> Otherwise, it's rather strange (and time consuming) to re-evaluate arguments
> each time.
> 
> ---------------------
> 
> ## Example 3 : outputs "hello folks"
> 
> #macro (print_twice $value)
> $value $value
> #end
> 
> #set ($myarray = ["hello","folks"])
> 
> #print_twice($myarray.remove(0))
> 
> ---------------------
>

Yes, that's a bit wacked.  However, you can imagine that the color tool
thing is something people might use.

I

> Depending on the followup, I'd be glad to try to contribute attenant patches.
> 
> Thanx for reading up to that point.
> And last but not least, thanx a lot to the support team.
> 
> Sincerely,
> 
> CloD
> 
> 
> 
> --
> To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>
> 

-- 
Geir Magnusson Jr.                                     [EMAIL PROTECTED]
System and Software Consulting
"They that can give up essential liberty to obtain a little temporary safety
deserve neither liberty nor safety." - Benjamin Franklin



--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to