问题
If I want to make a template that can accept 2 untyped
arguments, and pass them through do
notation, when I omit the second do
I'd like to have a way to specify a fallback in the form of a parameter's default value. as such:
template tpl(x: bool, body: untyped, bodyFinally: untyped): void =
if x: body
else: bodyFinally
#call site:
var r: int
tpl(true) do:
r = 2
do:
raise newException(Exception, "")
This works, but that:
template tpl(x: bool, body: untyped, bodyFinally: untyped = discard): void =
# same rest
Error: expression expected, but found 'keyword discard'
The default value is not accepted, and the message is weird, discard
is an expression isn't it.
Attmpts to workaround:
template tpl(x: bool, body: untyped, bodyFinally: untyped = proc()): void =
# same rest
Then we get:
Error: expression 'proc ()' is of type 'type proc (){.closure.}' and has to be discarded
I'm moderately ready to accept that, even though I find this discard
requirement uselessly pedant, and a nuisance of the language, since it's forcing us into uncomfortable gymnastics in generic code like here.
let's edit again:
template tpl(x: bool, body: untyped, bodyFinally: untyped = proc()): void =
if x: body
else: discard bodyFinally
And now the result is:
Error: internal error: expr(nkProcTy); unknown node kind
回答1:
It's true that there is no way to describe a block of code as a default parameter value. There are two possible work-arounds for this:
1) You can simulate the default values through an overload:
template tpl(x: bool, body: untyped, bodyFinally: untyped) =
if x: body
else: bodyFinally
template tpl(x: bool, body: untyped): void =
tpl(x) do:
body
do:
discard
Another shorter version of the second overload would be this:
template tpl(x: bool, body: untyped): void =
tpl(x, body, (discard))
2) You can use a default value like nil
that can be detected inside the template:
import macros
template tpl(x: bool, body: untyped, bodyFinally: untyped = nil) =
if x:
body
else:
when astToStr(bodyFinally) == "nil":
discard
else:
bodyFinally
Please note that I had to use astToStr
, because it won't be possible to compare bodyFinally
to nil
when the user supplies a non-default value.
来源:https://stackoverflow.com/questions/49613003/default-arguments-to-templates-expressions