I’ve got a couple Velocity macros like this:
#macro(Alpha)
#set($p = 1)
#@Beta()
$p // 1
$bodyContent
#end
#end
#macro(Beta $params)
#set($p = 2)
$p // 2
$bodyContent
#end
And I’m using them like so:
#set($p = 0)
#@Alpha(...)
$p // 3
#end
I believe this renders like so (ignore formatting): 2, 2, 2
But I’d like to have proper closure behavior, including more locally scoped names hiding parent scope names. In particular, the usage of $p labelled ‘3’ should refer to the value 0, ‘2’ to the value 2, and ‘1’ to the value 1.
Given proper closure semantics, it would print: 2, 1, 0
Is there any way to get this, or a way to implement a custom directive / modify #macro directive behavior to achieve this?
Velocity is a templating engine, not a proper programming language, so it’s a bit harder to grasp how it works.
Macros are not functions like in Java or C, meaning that invoking a macro isn’t going to create a new segment on the stack for local variables; velocity works with a context, and most of the time there’s just one global context.
Still, there are two ways of dealing with local variables:
velocimacro.context.localscopeconfiguration parameter that prevents changing global variables from within macros; note that this setting is deprecated and will be removed in Velocity 2.0$macrovariable as a local container for private variables if you enable themacro.provide.scope.controlconfiguration parameterStill, there’s another problem that would prevent your code from running correctly: Velocity macros work mostly as call-by-macro expansion, which means that the body passed to a macro isn’t evaluated first, then passed to the macro; it will be evaluated dynamically when the nested macro is executed. The code behaves as: