Recently I'd been trying to learn how to use rawProc. The documentation have stated that it could be useful, but not how it's used. It seems to return a pointer that points to a procedure, but it's unknown how many parameters that proc takes, of what calling convention it is. Also it seems to take an additional environment-pointer (as stated in the manual), but I didn't know if that should be the first or the last argument. So I decided to figure it out.
From the generated C code, I can see that a closure is consisted of a proc and an additional pointer (which is also stated in the manual). The underlying proc is {.nimcall.}. The environment is the last parameter, not the first.
When it is called, it's checked if the environment is nil, and if it is, the underlying proc is casted into another type and called without the environment pointer, otherwise it's called with the environment and other arguments.
The type which the underlying proc could be casted into is defined with N_CLOSURE_PTR, which, according to nimbase.h, is now an alias for N_NIMCALL_PTR.
Therefore the correct usage seems to be
import sugar
proc makeClosure(x: int): ((int) -> int) =
var n = x
result = (
proc(y: int): int =
n += y
return n
)
proc main =
var
c1 = makeClosure(10)
e = c1.rawEnv()
p = c1.rawProc()
if e.isNil():
let c2 = cast[proc(y: int): int {.nimcall.}](p)
echo c2(2)
else:
let c3 = cast[proc(y: int, env: pointer): int {.nimcall.}](p)
echo c3(3, e)
main()
A PR to modify system.nim, in the devel branch? I'm not good at using git.
Also, is there a preferred way to check if a closure iterator has finished iteration, by using only that two pointers? Or are they not intended to be used without the original closure variable? The way I learned from C code is cast[ptr UncheckedArray[int]](env)[1], where env is the environment pointer, but this doesn't seem to be an API.
Note that you can also do it entirely via github without having to use git yourself, assuming this applies to only one file. Just go to the docs of rawproc (https://nim-lang.org/docs/system.html#rawProc%2CT) and click on the edit button. You'll get to an edit surface provided by github themselves. Look for rawProc and edit the doc comment there.
You can improve the situation even further by also writing a runnableExample (https://nim-lang.org/docs/system.html#runnableExamples%2Cstring%2Cuntyped) for the correct useage in there! You'll see whether that works or not in the test-runs nim will start afterwards.