In Nim 1.0, a fix was made to disallow declaring a template of an untyped parameter more than once. That is, this is now disallowed
template foo(x: untyped) = discard
template foo(x: untyped) = discard
This is correct, and one may wonder why it was allowed before. Unfortunately, it turns out I had used this pattern in memo, inadvertently, as it was generated by a macro. Or maybe it comes from some PR I accepted, I dno't recall exactly. But it turns out that memo generates code like this
template resetCache(x: untyped) =
when x == someFunction:
# do stuff
template resetCache(x: untyped) =
when x == someOtherFunction:
# do stuff
template resetCache(x: untyped) =
when x == YetAnotherFunction:
# do stuff
As you can see, there is a when guard, which guarantees that at most one of the templates will apply for a given function. But still, the generated code does not make sense, and does not compile.
The intention here is to memoize functions - that is, store computed values in a hash table - and be able to reset that hash table when needed. In other words, the declaration
proc f(x: int): int {.memoized.} =
# body here
is translated into something like
var table12345 = initHashTable[int, int]()
proc f12345(x: int): int =
# body here
proc f(x: int): int =
if not x in table12345:
table12345[x] = f12345(x)
return table12345[x]
template resetCache(x: untyped) =
when x == f:
table12345 = initHashTable[int, int]()
where the names table12345 and f12345 are gensymmed.
What could be a way to prevent the name clash? I could collect all associations function -> cache at compile time, but then I need some way to generate a single resetCache template before it is used.
Right now, memo does not compile, and I am trying to fix it as I have been updating all my libraries for Nim 1.0 compatibility.
You can use identifier construction
template foo(x: untyped) =
template `resetCache _ x`() =
# do Stuff
template resetCache(x: untyped) {.genSym.}
@cdome: the problem of using gensym is that - well, users have to be able to call this function, they could not with a generated name.
@mratsim Your solution should work. It is not really optimal to generate a function with a magic name such as resetCacheFib() but if there are no other solutions, I am going for it, thank you!
template foo(x: untyped) =
template `resetCache x`() =
echo "Success"
foo(Fib)
resetCacheFib()
I am wondering as well... maybe it didn't? :-D
In any case, I have updated memo per @mratsim's suggestion, it seems the best approach for now
I agree that those ad-hoc functions are a pain when you need to debug a shared codebase.
I know that I struggled with some on the Nimbus codebase where the generator was called ceilXX and the generated where ceil32, ceil64 ... and I always had trouble checking them out.
Hopefully nimsuggest gets better hint