Is there a Hash-like data structure that's not referencing its own elements?

Thanks, the “one off” shouldn’t really hurt, you’re right.
But it doesn’t seem to work for me (Crystal 1.8.1 on Ubuntu)…

class X
    def initialize
        GC.before_collect do
        end
    end
end

X.new
GC.collect

… leads to…

Stack overflow (e.g., infinite or very deep recursion)
[0x55c2e81c47c6] *Exception::CallStack::print_backtrace:Nil +118 in .../snap/crystal/common/.cache/crystal/crystal-run-gc.tmp
[0x55c2e81b3ff6] ~procProc(Int32, Pointer(LibC::SiginfoT), Pointer(Void), Nil) +310 in .../snap/crystal/common/.cache/crystal/crystal-run-gc.tmp
[0x7fdd94d39980] ?? +140589661395328 in /lib/x86_64-linux-gnu/libpthread.so.0
[0x55c2e81b13c1] ~procProc(Nil) +17 in .../snap/crystal/common/.cache/crystal/crystal-run-gc.tmp
[0x55c2e81b14c7] ~procProc(Nil) +279 in .../snap/crystal/common/.cache/crystal/crystal-run-gc.tmp (140587164552344 times)
[0x55c2e823dd10] GC_mark_some +1392 in .../snap/crystal/common/.cache/crystal/crystal-run-gc.tmp
[0x55c2e823693d] ?? +94295606651197 in .../snap/crystal/common/.cache/crystal/crystal-run-gc.tmp
[0x55c2e8236719] GC_try_to_collect_inner +329 in .../snap/crystal/common/.cache/crystal/crystal-run-gc.tmp
[0x55c2e82374a8] ?? +94295606654120 in .../snap/crystal/common/.cache/crystal/crystal-run-gc.tmp
[0x55c2e823751a] GC_gcollect +10 in .../snap/crystal/common/.cache/crystal/crystal-run-gc.tmp
[0x55c2e81d9346] *GC::collect:Nil +6 in .../snap/crystal/common/.cache/crystal/crystal-run-gc.tmp
[0x55c2e81a3d2b] __crystal_main +1051 in .../snap/crystal/common/.cache/crystal/crystal-run-gc.tmp
[0x55c2e8235c96] *Crystal::main_user_code<Int32, Pointer(Pointer(UInt8))>:Nil +6 in .../snap/crystal/common/.cache/crystal/crystal-run-gc.tmp
[0x55c2e8235c0a] *Crystal::main<Int32, Pointer(Pointer(UInt8))>:Int32 +58 in .../snap/crystal/common/.cache/crystal/crystal-run-gc.tmp
[0x55c2e81b12d6] main +6 in .../snap/crystal/common/.cache/crystal/crystal-run-gc.tmp
[0x7fdd940e2c87] __libc_start_main +231 in /lib/x86_64-linux-gnu/libc.so.6
[0x55c2e81a382a] _start +42 in .../snap/crystal/common/.cache/crystal/crystal-run-gc.tmp

Hm… right, sorry. GC.before_collect might not be ready for this. It seems it does not accept an arbitrary number of calls, only the one that is currently in place. Procs passed end up calling itself because of limitation on how before_collect is currently written to avoid generating closures.

If we need to hook on before collect we need to offer a better API for it.

it just occurred to me that this is also the proper general (long-living) caching data structure (vs. Hash). :smiley:
Because the GC cleans the cache if the objects are no longer existing.
At least for class instance related data…

We should just remove any enumeration-/indexing-like methods from this class (can lead to non-deterministic behavior), to have it just serve as a mapper.