On Mon, May 3, 2010 at 9:16 AM, Sergiu Dumitriu <[email protected]> wrote: > On 05/03/2010 04:45 PM, Nathan Bubna wrote: >> >> 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. > > +1 for 100% compliant call by sharing (java behavior). At least we'll know > what to expect. > > Still, the "macro" name suggests a call-by-macro behavior, should it be > renamed to something else? Leave #macro as it is (for backwards > compatibility), deprecate it, add a new #function or something?
I suppose it does somewhat, but i don't think we need to bow to that. Balancing forward motion and backward compatibility is always tricky with a 2.0. You can toss out some old things, but there is a price for that even so. I'd be inclined to keep the name #macro, even if/when we change this. Giving up any of the main directive names seems a bit too dramatic, even for 2.0. >> 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. > > Done at http://wiki.apache.org/velocity/MacroEvaluationStrategy , but I have > no idea where to link it from. Thank you! Linking from the email archives is the best start. I would also drop the link into VELOCITY-681 and VELOCITY-684 so that people looking at those have the reference too. --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
