Working in Nim, my intuition for templates is that, at compile time, they are simply expanded into their code (with the appropriate substitutions). But the following code:
type
New_Type = ref object of RootObj
template Template_Procedure(T: untyped, vProc: bool = true) =
proc ProcedureA(self:var T, vInt: var int): int
when vProc == true:
proc ProcedureA(self:var T, vInt: var int): int =
var tReturn = vInt * vInt
return tReturn
proc ProcedureB(self: var T, vInt: var int): int =
var tI = ProcedureA(self, vInt)
return 2 * tI
Template_Procedure(New_Type, vProc = false)
proc ProcedureA(self:var New_Type, vInt: var int): int =
var tReturn = vInt * vInt * vInt
return tReturn
var tNew = new(New_Type)
var tInt = 5
echo $ProcedureB(tNew, tInt)
gives the error:
test3.nim(9, 10) Error: implementation of 'test3.ProcedureA(self`gensym0: var New_Type, vInt`gensym0: var int)' expected
If however I instead call
Template_Procedure(New_Type, vProc = true)
then there are no errors.
In contrast, if I manually substitute the text of the template in for the place where it is called, then the opposite occurs. I.e. the code compiles if I substitute false for vProc and I get the error
Error: redefinition of 'ProcedureA'; previous declaration
if I substitute true for vProc.
Can someone explain to me where my intuition is incorrect regarding templates? (or give me appropriate references)
Also, is there a way to write code which at compile time is simply expanded?
Specifically I would like to be able to call Template_Procedure(X, vProc = false) where X is a type and then, for appropriate types X, manually write specific
ProcedureA(self: var X, vInt var int): int
procedures. And for other X simply call Template_Procedure(X) and not have to manually define ProcedureA.
The forward declare never gets an implementation as templates are hygienic. Although they both appear to have the name ProcedureA
since you are inside template space they are not named the same. You likely should mark the template {.dirty.}
or use {.inject.}
on the procedures to inject the symbol names.
To the following question I do not know what you mean, templates are simply expanded.