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]

Reply via email to