template outerT*(s: string, body: stmt) =
var strg = s
echo "outerT's strg=", strg
body
outerT "me":
echo "me's strg=", strg
And was surprised it would not compile, complaining undeclared identifier:
test2.nim(7, 29) Error: undeclared identifier: 'strg'
After much head scratching I figured out why and rewrote it like this:
template outerT*(s: string, body: stmt) =
var strg = s
echo "outerT's strg=", strg
body
var strg = "top level strg"
outerT("me", echo("me's body says hi ", strg))
And the output shows that "me's" body is a closure on the top level:
./tests/bin/test2 outerT's strg=me me's strg=top level strg
Writing the code using the "special syntax", as in the first code-block, really looks like the closure would be inside the template of outerT. It becomes obvious when I rewrote it with the "normal syntax" that my expectation was wrong.
Does there happen to be a way to allow the closure of the last statement parameter be inside the template when using the "special syntax" or maybe via a pragma? I suspect not, in which case has it been considered?
Hi @winksaville,
The undeclared identifier in your first code example should not be too surprising. In the Templates section of the Nim manual, the subsection Hygiene in templates begins:
"Per default templates are hygienic: Local identifiers declared in a template cannot be accessed in the instantiation context"
After a code example, it continues:
"Whether a symbol that is declared in a template is exposed to the instantiation scope is controlled by the inject and gensym pragmas: gensym'ed symbols are not exposed but inject'ed are.
The default for symbols of entity type, var, let and const is gensym and for proc, iterator, converter, template, macro is inject. However, if the name of the entity is passed as a template parameter, it is an inject'ed symbol"
and finally:
"To get rid of hygiene in templates, one can use the dirty pragma for a template. inject and gensym have no effect in dirty templates."
So the {.dirty.} pragma may be a brute-force way to obtain the effect you want. Alternately, you could experiment with the {.inject.} pragma when you declare variables inside the template.
The section on Ordinary vs immediate templates might also be useful, if you want to pass the identifier strg into the template before it's been declared. (You would annotate the template with the {.immediate.} pragma.)
Have I correctly understood your question?