Hello community! I am a new and enthusiastic user of nim, which now I'd like to go to the next step.
I am trying to use nim to call the Parallel's C API, to manage my virtual machines in the comfort and flexibility of nim. This means that I have to keep reference of obscure pointers to virtual machines (!!!) and free them (a) when something goes wrong and (b) when they are not needed any more.
For the (a) part, I was thinking to wrap this pointer on a nim object, which could be "invalidated" if something goes wrong, to be on the safe side.
My question is mainly for the second part. In the documentation ("Nim Backend Integration") mentions
Typically C data structures have their own malloc_structure and free_structure specific functions, so wrapping these for the Nim side should be enough.
But I haven't found a way to tell nim that "do this when you want to take the object out of memory". Also, is this code and GC guaranteed to be called when exiting nim (or when ctr-c is hit) to be on the safe side, or something more should be done?
Thank you for your attention!
Thank you for the hint!
So, if I got it correctly, since it is "impossible" to copy the whole resource around (you can't just copy a virtual machine!), a right strategy would be to use internal reference counting as an unowned ref type (as described in https://nim-lang.org/docs/destructors.html#owned-refs ) ?
Or is this something like this supported already in nim?
You can use
proc `==`(dst: var MyVM, src: MyVM) {.error: "One cannot simply copy a VM".}
to ensure at compile-time that your VM are never copied, only moved.
For "do this on destruction":
type MyVM = object
# A wrapper to the C type "vm_t"
p: ptr vm_t
proc `=destroy`*(vm: var MyVM) =
if vm.p.isNil:
return
vm.p.releaseVM() # assuming the proc to release the VM is this
vm.p = nil
For "do this on move"
proc `=sink`*(dst: var MyVM, src: MyVM) {.inline.} =
doThis()
# And now move the pointer
system.`=sink`(dst.p, src.p)
Thank you for your answer.
I suspect in the first proc you mean `=` instead of `==` ?
Also, I am sorry to ask you, the doThis() in the =sink proc, why is it needed? Shouldn't the pointer copy be enough? Something like
proc `=sink`(dest: var MyVM; source: MyVM) =
dest.p = source.p
`=destroy`(dest)
Note, I have reversed the pointer copy with the =destroy, because it makes more sense to me first to copy the pointer and then to make it nil.
Yes sorry just =
The =sink is optional as mentioned in the destructors document. But if you have a special doThis processing you want to do on move that's where you put it.
Note that if you implement your own =sink, you need to destroy the destination first before assigning the new source pointer or your destructors won't be called properly.