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]
