Nim developer here, I'm glad to see so much enthusiasm for Nim. I'm currently writing a book about it called Nim in Action[1] and would love to know what you guys think about it. The first chapter is free[2], so even if you don't intend to buy it you can still take a look at it.
We also have a BountySource campaign[3], so if you would like to support us please consider making a donation.
I wonder how Nim's cycle detection work? It is said in the docs that Nim never scans the whole heap, but I believe in worst cases you have to scan the whole heap to detect cycles.
Also how does the gc trace variables on the stack? How do you determine if a value is a pointer to an object or an integer?
Good questions. I'm afraid the documentation is seriously out of date about the GC: It used to implement a variant of "trial deletion" so that "never scans the whole heap" used to refer to the fact that it doesn't use traditional mark&sweep, but only scans the subgraph(s) leading to the cycles. Of course you can always create a "subgraph" that spans the whole heap, so even for trial deletion it is a dubious claim.
Since version 0.14 (iirc) however, Nim uses a traditional mark&sweep backup GC to collect cycles. Reasons: Trial deletion in practice is much slower.
For all versions of the GC is stack is scanned conservatively as precise stack scanning is simply too expensive when C is your main target.
That has been my experience too. That all the extra work and logic (cause the algorithm is complicated) you need for detecting cycles and trial deletion is so expensive that regular mark&sweep beats it.
But to ask a pointed question, doesn't that mean Nim gets the worst of both worlds? You have both the overhead of updating reference counts and the (relatively long) garbage collection pauses. I guess if the programmer codes in such a way that no cyclic garbage is created it is not a problem because the gc will never be triggered. But how common is that in practice? Does the language make it easy to avoid cycles?
> But to ask a pointed question, doesn't that mean Nim gets the worst of both worlds? You have both the overhead of updating reference counts and the (relatively long) garbage collection pauses.
There's a patch of the collector to make the M&S incremental, to avoid pauses for this step too. Of course, whether a deferred RC'ing GC with incremental cycle collector works better in practice than a more conventional generational incremental GC (or just an incremental GC) is an open question. :-)
Nim has garbage collected pointers (ref) and raw pointers (ptr). You can use 'ptr' to break up cycles manually and disable the M&S. I suppose it's very much comparable to Swift except that Nim's RC overhead is much lower since it's deferred RC.
We also have a BountySource campaign[3], so if you would like to support us please consider making a donation.
Finally, please feel free to AMA!
1 - https://manning.com/books/nim-in-action?a_aid=niminaction&a_...
2 - https://manning.com/books/nim-in-action?a_aid=niminaction&a_...
3 - https://salt.bountysource.com/teams/nim