And, technically, GCs collect non-garbage, and throw away what remains. They don’t care whether what they throw away contains cycles or not, but have to take care that they don’t keep running in circles when they follow links between objects while collecting the non-garbage.
I don't understand why you said that.
See https://en.wikipedia.org/wiki/Tracing_garbage_collection#Na%...
And yes, you're correct that GCs handle cycles without issue (that's a large part of the reason to use tracing GC over other memory management strategies like ObjC's auto-reference counting).
[1]: https://en.wikipedia.org/wiki/Cycle_detection#Floyd.27s_Tort...
Still, fun algorithm.
Otherwise traditional GC use a copying mechanism, what doesn't end up copied is dead.
The old reference counting GC in Nim had that extra copying pass when a type could have cycles.
That said, it's very easy to tell if a type can have cycles or not at compile-time, you just need to check if it refers to itself i.e. does the Node type has a Node field (or a field that can recursively contain a Node field).
Certainly useful at times as I suppose it may be used to ensure you don't have cycles (I imagine that could be useful for resource management) but 'can have cycles' is definitely not 'does have cycles'. It's the latter that's important here.
In the future we might have formal verification helping as well: https://nim-lang.org/docs/drnim.html
Cycle detection at point of creation (when a pointer is set). You can do a full scan of data structure graph after every malloc but that's equivalent to your GC, and clearly horribly, unacceptably expensive.