I have a compile time proc p which I'd like to use in a static context:
proc p (s:string):NimNode {.compileTime.} =
bindSym(s)
static:
let t = "SomeType"
echo p(t).repr
but this errors with:
Error: cannot evaluate at compile time: s
Changing the argument type to static gets past that error but now I am unable to call it in a static block:
proc p(s:static[string]):NimNode {.compileTime.} = ...
static:
let t = "SomeType"
echo p(t).repr
because s in the static block is a string and the p expects a static[string]:
Error: type mismatch: got <string>
but expected one of:
proc p(s: static[string]): NimNode
first type mismatch at position: 1
required type for s: static[string]
but expression 'x' is of type: string
I think I maybe missing something basic because I don't see why:
The following with simply using const instead of let works :
proc p(s:static[string]):NimNode {.compileTime.} = ...
static:
let t = "SomeType"
echo p(t).repr
const is the Idiomatic way to declare compile time variable in Nim.
let is used to declare immutable variable.
Again, this is specific to bindSym. bindSym has to check the local context for symbols, and this context isn't available when "evaluating" constant expressions, only "compiling" them, so bindSym was originally made to use this context directly when "compiling" them. What dynamicBindSym does is it stores the local context when "compiling" them into a closure, then this closure is called when "evaluating" it.
The difference is that compile-time code with variable parameters (including macro code) is only compiled once, and evaluated multiple times. That's why it still needs to be "dynamic".
I get the use of const outside a static block but inside one in a language like Nim that doesn't have any stages above "compile time" it doesn't make any sense to me that it is different from let. My guess is the compiler isn't propagating that information when it supplies the argument to the proc.
In any case dynamicBindSym fixed my issue but having that const trick in my back pocket is useful. Thanks everyone, this has been very informative.
in a language like Nim that doesn't have any stages above "compile time"
Then how could i do this
static:
const a = static:
let b = static:
var c = static:
2 * 2
static: assert not(c is static)
c - 1
static: assert not(b is static)
b / 2
static: assert a is static
echo a
A bit offtopic, but this is the kind of explanation for these sort of features that would really help a lot to have written up in the manual.
I refuse to mention dynamicBindSym until I can foresee its consequences for the Nim spec and implementation.