0

In Nim templates: as a follow-up from this problem, I had the idea of working around the default-argument unavailability by using overloading, or even in this case, plain wrapping. Though, it would be too good if something didn't hit the fan again, let me share:

Notice that bodyFinally is now a hard (must specify) argument.

template tpl(x: bool, body: untyped, bodyFinally: untyped): void =
  if x: body
  else: bodyFinally

# we add a convenience helper with 2 args here.
template tpl2(x: bool, body: untyped): void =
  tpl(x) do:
    body
  do:
    discard

#call site:
var r: int
tpl2(true) do:
  r = 2

cool (it works). Though this was not my first shot for tpl2; this was:

template tpl2(x: bool, body: untyped): void =
  tpl(x, body, discard)

Because that's what do supposedly rewrites the thing anyway. Except we get:

Error: expression expected, but found 'keyword discard'

So what's up with that ?

v.oddou
  • 6,476
  • 3
  • 32
  • 63

1 Answers1

3

It's a bit complicated to explain why, but you could have written the overload like this:

template tpl(x: bool, body: untyped, bodyFinally: untyped) =
  if x: body
  else: bodyFinally

template tpl(x: bool, body: untyped): void =
  tpl(x, body, (discard))

var r = 1

tpl(false):
  r = 2

echo r

tpl(true):
  r = 3

echo r

The extra brackets trigger a special parsing rule producing nkStmtListExpr AST node, which is a valid input for the template here. This construct is usually used in C-style if statements that include an assignment followed by a NULL-test:

if (let f = fopen(...); f != 0):
  # do something with `f`

As expected, the output of running the above program will be:

1
3
zah
  • 5,314
  • 1
  • 34
  • 31