I encountered this problem a while ago and it's not really important to me right now, but I just want to make sure of some things before I forget about it.
The times module uses FFI for its procs, same as io (exported by the system module). Except the system module also has slurp/staticRead and gorge/staticExec, which are simple magics for reading files and executing processes in compile time thanks to the compiler.
What I'm asking is, could there ever be a staticTime proc analog to times.getTime, or will we have to use a compile time FFI feature when/if it arrives? It is technically possible to use staticExec in current Nim for the same task but it seems too resource demanding. A hook like staticTime would be useful for things like benchmarking macros, NimScript etc. This feels like it should have been discussed before and I do remember it being discussed specifically for NimScript, but I just can't find anything on it.
staticExec is a bad approach to solve this kind of problem more generally (whether it's for regex, rand, getTime, and hosts of other things that require importc procs).
In the end you end up duplicating existing functionality for no gain.
Introducing a static overload in vmops is often a good thing, but what's bad is renaming it differently when it is a simple CT wrapper that does the exact same thing at CT, eg foo=>staticFoo.
A common argument in favor of renaming is to prevent against user errors when they write const a = foo(), and intended to write let a = foo(), however that's just the desired behavior here, const vs let have different, well understood semantics.
Renaming is bad because code that works at RT should work at CT as much as possible, otherwise useful functionality is lost when needed at CT and we have to re-invent the wheel or use silly workarounds like when nimvm to undo the distinction eg:
template runBench(fun)
when nimvm: let t = staticTime()
else: let t = getTime()
fun()
...
All that's needed, more generally, is a flag --enablevmops:Foo if we want to disable by default some features at CT, but we should not rename them unless their CT behavior is modified (like staticRead etc)
# import std/timers # pending https://github.com/nim-lang/Nim/pull/13617
include system/timers
proc main(): auto =
let t1 = getTicks()
# run some code
let t2 = getTicks()
# echo t2.int64 - t1.int64 # works but we should used timers.`-`
# echo t2-t1 # Error: cannot evaluate at compile time: timeBaseInfo
result = (t1, t2)
const (t1, t2) = main()
echo ("nanos: ", t2 - t1)
this works today; it could be improved so that t2-t1 also works in VM so we wouldn't need to return the tuple, but that should be fixable as future enhancement to CT FFI
you can also use cpuTime at CT via --benchmarkVM However, it should error instead of giving an arbitrary result as it does right now when --benchmarkVM is not passed:
if optBenchmarkVM in c.config.globalOptions:
wrap0(cpuTime, timesop)
else:
proc cpuTime(): float = 5.391245e-44 # Randomly chosen
wrap0(cpuTime, timesop)
@timothee
Just adding {.push experimental: "vmopsDanger".} to the script's top does not change anything.
Adding --experimental:vmopsDanger as a CLI flag fixes the importc error, but it creates another error, instead.
times.nim(1307, 6) Error: cannot evaluate at compile time: localInstance
import std/times
static:
# must compile with --experimental:vmopsDanger
# echo getTime() # error cannot evaluate at compile time: localInstance
let x = getTime()
echo x.toUnix
echo x.repr
# time something here
echo getTime() - x