Templates
27.1 What Templates Are
Hygienic, AST-level substitutions. They're like inline macros without AST manipulation code. They're expanded at the call site.
template `!=`(a, b: untyped): untyped = not (a == b) # how the stdlib defines it
template withLock(l: Lock, body: untyped) =
acquire(l)
try:
body
finally:
release(l)
withLock myLock:
counter += 127.2 untyped vs typed Parameters
untyped: the argument isn't type-checked before substitution (allows new identifiers and arbitrary code blocks).
typed: the argument is semantically checked first.
template declareInt(name: untyped, val: int) =
var name = val
declareInt(answer, 42)
echo answer
template measure(label: string, body: untyped) =
let t0 = cpuTime()
body
echo label, ": ", cpuTime() - t0, "s"
measure "sorting":
data.sort()27.3 Hygiene, inject, gensym, dirty
template withFile(f, filename: untyped, mode: FileMode, body: untyped) =
let f = open(filename, mode) # `f` is injected because it's a parameter name
try: body
finally: f.close()
template defineHelper() =
var helperVar {.inject.} = 1 # visible to the caller
var hidden = 2 # gensym'd: not visible
template unsafeTpl() {.dirty.} = # no hygiene at all
echo x27.4 Lazy Evaluation
template debugLog(msg: string) =
when not defined(release):
echo msg # `msg` is evaluated only when the branch is compiled in
template `??`(a, b: untyped): untyped =
let x = a
if x.isSome: x.get else: b # b is evaluated lazily