And the moral of the story is that VTL is that getting creative with
macro args is only for the brave...  simplicity is a good goal.

(more response inline)

On Mon, May 3, 2010 at 3:25 AM, Sergiu Dumitriu <[email protected]> wrote:
> Hi devs,
>
> Looking at the various standard evaluation strategies (see
> http://www.knowledgerush.com/kr/encyclopedia/Call-by-something/ and
> http://en.wikipedia.org/wiki/Evaluation_strategy ), none of them applies to
> Velocity. It's a mix between call by macro expansion, call by sharing, call
> by value and other behaviors.
>
>
> Call by sharing example (new in 1.7b1, and shortly only in 1.6.1)
> #macro(callBySharing $x $map)
>  #set($x = 'a')
>  $map.put('x', 'a')
> #end
> #set($y = 'y')
> #set($map = {})
> #callBySharing($y $map)
> $y -> 'y' (but is 'a' in 1.6.2, 1.6.0 and before)
> $map.x -> 'a'
> Java-like behavior.
> See https://issues.apache.org/jira/browse/VELOCITY-681

Yeah, i think we've got this right now.  Global context, no magic
proxying.  Simple, unsurprising.

> Call by name/macro expansion example (and call by need counter-example)
> #macro(callByMacro1 $p)
>  not using
> #end
> #macro(callByMacro2 $p)
>  using: $p
>  using again: $p
> #end
> #set($x = [])
> #callByMacro1($x.add('t'))
> $x -> [], the add call was not executed
> #callByMacro2($x.add('t'))
> $x -> [t,t], the add call was executed twice
> This is a classic call by name example.

I've never been a big fan of this.  I think my very first email to the
list so many eons ago was a complaint about it. :)  It is surprising,
and i just don't see much benefit or any use-case that makes this
necessary.  I wouldn't mind seeing this change in 2.0...

> Call by value(?) example (and call by name or expansion counter-example)
> #macro(callByValueSwap $a $b)
>  $a $b becomes ##
>  #set($tmp = $a)
>  #set($a = $b)
>  #set($b = $tmp)
>  $a $b
> #end
> #callByValueSwap('a', 'b') ->
> a b becomes b a
> In a true call-by-name (or macro-expansion) implementation, $a would always
> be 'a'. What actually happens is that #set($a = $b) creates the global
> variable $a which shadows the formal parameter. This is a bit strange, since
> formal parameters should never be shadowed by external parameters.

I don't think they do unless the user has indicated they wish to
change that formal arg, in which case, this is less surprising.  I
don't care what true call-by-name says.  If the user wants to change
it, we should let them.

> Call by macro expansion example (and call by value or sharing
> counter-example)
> #macro(changeMap $map)
>  Before: $map.someKey
>  #set($map.someKey = 'new value')
>  After: $map.someKey
> #end
> #changeMap({'someKey' : 'old value'}) -> old value, then again old value
> If this was true call-by-sharing (or call-by-reference), then $map would be
> a pointer to a real map which would be changed by the first set. See
> https://issues.apache.org/jira/browse/VELOCITY-684

Yeah, i still say what i said in the issue comments.  We should let
the user change it if that's clearly what they want.  I see no point
to strictly following call-by-name here where it is so dramatically
counter-intuitive.

> Call by macro expansion example (exposes name capture, call by name
> counter-example)
> #macro(nameCaptureSwap $a $b)
>  $a $b becomes ##
>  #set($tmp = $a)
>  #set($a = $b)
>  #set($b = $tmp)
>  $a $b
> #end
> #set($x = 'a')
> #set($tmp = 'b')
> #nameCaptureSwap($x $tmp) ->
> a b becomes a a
> This is the classic name capture example, which only happens with call by
> macro expansion.
>
>
> Mixing different types of actual and formal parameters will expose mixed
> behaviors.
>
>
> In conclusion, Velocity macros work mostly as call-by-macro expansion
> internally, with call-by-sharing external behavior, but affected by
> automatic assignment of global variables when local variables can't be
> assigned (using a non-lvalue as an lvalue). I haven't tested strict mode, so
> I don't know what evaluation strategy is used in that case.
>
>
> So, the question would be, should Velocity choose and stick to one of the
> classic evaluation strategies? Should the current behavior be kept as-is? In
> the latter case, it should be well documented to avoid surprises. Well, it
> won't actually avoid surprises, but at least there will be a piece of
> documentation to point to.

i, of course, think VELOCITY-684 should be resolved as i suggested in
the 1.x timeframe, but i'm unlikely to get to it myself and no one
else is stepping up to do that.   in 2.x, i think we should seriously
consider dropping our modified call-by-name behavior, unless someone
can give a compelling reason to keep it.

documentation is great either way.  Sergiu, perhaps you would be so
kind as to adapt this email for the wiki?  It does a great job of
covering the corner cases and pointing people to the relevant issues
where they can advocate change.

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to