Wow, there are a lot of ways to write unmaintainable code.
Do all of those examples work as you describe? (in the current version)
Sergiu Dumitriu wrote:
On 05/02/2010 09:01 PM, Caleb James DeLisle wrote:
I've been using that pattern everywhere.
There are no return statements
the only other options I see are making all variables global to the script
or eliminating the use of macros entirely (spaghetti code).
Is there a better way?
This only affects things like this:
I have been using this:
#set($output = '')
#getData($input, $output)
#if($output == '')
## error
#end
#macro(m $returnParam)
#set($returnParam = 'result')
#end
#m($expectedOutput)
$expectedOutput is not 'result'
These will still work:
Although I knew this worked, I have avoided this at all cost.
Global variables are too hard for me to follow.
#macro(m)
#set($returnParam = 'result')
#end
#m()
$returnParam is 'result'
Or:
I have used this a few times.
#set($output = {})
#macro(m $output)
$output.put('expectedOutput1' : 'result1')
$output.put('expectedOutput2' : 'result2')
#end
#m($returnParam)
$returnParam.expectedOutput1 is 'result1'
$returnParam.expectedOutput2 is 'result2'
The first one is not nice since it has side effects which must be well
documented, the second one is nicer but also needs to be documented and
it needs a map or array even if only one output is expected.
The way velocity macros work is a bit unclear, it's a mix between call
by macro expansion, call by sharing, call by value and other behaviors.
See
http://en.wikipedia.org/wiki/Evaluation_strategy and
http://www.knowledgerush.com/kr/encyclopedia/Call-by-something/ for
short explanations.
Call by sharing example (in 1.7b1 only)
#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)
$map.x -> 'a'
Java-like behavior
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
I did not know about this.
Maybe some of these gotchas should be added to the scripting page.
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.
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.
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.
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.
Thanks for all of the info.
The fact that we're having this discussion probably means it's time to implement
a
security manager so we can run non PR jsr223 script but I'm not sure how to prevent
DoS attacks like vacuuming up the heap or stack overflowing the garbage collector.
Caleb
Sergiu Dumitriu wrote:
> Lots of goodies, but we can't upgrade until we fix the bad usage of
> macros, see
https://issues.apache.org/jira/browse/VELOCITY-681
>
> On 05/01/2010 06:20 PM, Vincent Massol wrote:
>> fyi
>>
>> -Vincent
>>
>> Begin forwarded message:
>>
>>> From: Nathan Bubna<nbubna(a)apache.org>
>>> Date: April 28, 2010 12:53:50 AM GMT+02:00
>>> To: Velocity Developers List<dev(a)velocity.apache.org>rg>, Velocity Users
List<user(a)velocity.apache.org>rg>, announce(a)apache.org
>>> Subject: [ANNOUNCE] Velocity Engine 1.7-beta1 release available
>>>
>>> The Velocity developers are please to announce the availability of
>>> Velocity Engine 1.7-beta1.
>>>
>>> Downloads can be found here:
>>>
http://velocity.apache.org/download.cgi
>>>
>>> A great deal of work has been done since the 1.6 branch. Here's a
taste:
>>>
>>> - Your macros can now be called with bodies when you want:
>>> #macro(foo)Here is $bodyContent#end
>>> #@foo()body content!#end
>>> - Quotes can be escaped in strings by doubling them:
>>> #set( $foo = "$person said, ""$comment""
" )
>>> #set( $bar = 'Joe said, ''Hi!'' ' )
>>> - The flawed #literal directive has been replaced with:
>>> #[[ This is included but not parsed, so #if and $foo need no
escaping.]]#
>>>
>>> Also included are namespacing improvements, better #break and #stop,
>>> bracketed index syntax, and more! For full details, please see the
>>> change log:
>>>
http://velocity.apache.org/engine/devel/changes-report.html
>>>
>>> This should work as a drop-in replacement for Velocity 1.6.3 in the
>>> vast majority of cases. However, there have been a number of
>>> deprecations (should result in warnings in your log output) and a few
>>> minor behavioral changes, all of which are explained in the change
>>> log. :)