Maybe I am misunderstanding something, as I have never used destructors in Nim. Still, I am a little confused.
In the following example, the echo inside the destructor never happens, altought I would expect it to be called
type
Foo = object
x: int
RFoo = ref Foo
proc makeFoo(x: int): RFoo =
new result
result.x = x
proc `=destroy`(o: Foo) =
echo "destroying ", o.x
when isMainModule:
block:
let f1 = makeFoo(5)
var f2 = Foo(x: 5)
echo f1.x
echo f2.x
echo "done"
Thank you, it seems that I was using an old version of Nim on my PC at home. Now I am able to run destructors.
What about the effect of finalizers? I am trying this version
{.experimental.}
type
Foo = object
x: int
RFoo = ref Foo
proc finalizeFoo(f: ref Foo) {.nimcall.} =
echo "finalizing ", f.x
proc makeFoo(x: int): RFoo =
new result, finalizeFoo
result.x = x
proc `=destroy`(o: Foo) =
echo "destroying ", o.x
when isMainModule:
block:
let f1 = makeFoo(5)
var f2 = Foo(x: 7)
echo f1.x
echo f2.x
GC_fullCollect()
echo GC_getStatistics()
echo "done"
but the finalizer is not called, although I force a full GC.
Is there a way to make sure a finalizer is called? Not that I need to run the finalizer deterministically - I just want to experiment with the semantics of destructors and finalizers to understand better when to use which
Just moving the block part into a separate function seems to work OK.
I guess that there still must be some reference to f1 in the case of using the block statement. That would prevent the garbage collector from reclaiming it.
...
proc main() =
let f1 = makeFoo(5)
var f2 = Foo(x: 7)
echo f1.x
echo f2.x
when isMainModule:
main()
GC_fullCollect()
echo GC_getStatistics()
echo "done"
output:
5
7
destroying 7
finalizing 5
[GC] total memory: 528384
[GC] occupied memory: 57344
[GC] stack scans: 1
[GC] stack cells: 0
[GC] cycle collections: 1
[GC] max threshold: 4194304
[GC] zct capacity: 1024
[GC] max cycle table size: 0
[GC] max stack size: 104
[GC] max pause time [ms]: 0
done