Garbage Collection Without Unsafe Code

(fitzgen.com)

82 points | by foota 3 days ago

6 comments

  • ltratt 4 hours ago
    It would really be good if someone could provide an updated overview of all of the "GCs for Rust" created thus far -- for a while I tried to keep up with them, but there are just too many! When we wrote the Alloy paper, we took Manish's survey as a starting point, and covered as many GCs of different kinds as we could squeeze in [1]. But even then there was no way we could squeeze _everything_ in, and I've seen at least 2 or 3 new ones since (safe-gc is older than the Alloy paper, so I'm not including it in that count)!

    [1] https://soft-dev.org/pubs/html/hughes_tratt__garbage_collect...

    • pjmlp 3 hours ago
      If anything all those attempts prove that for many scenarios, it is better having automated resource management + (affine, linear, dependent, effects) than the pure affine types approach taken by Rust.

      Hence all the Chapel, Swift, D, Linear Haskel, Ox, Idris2, Scala Capture Checking, Koka, and probably many others, efforts going on.

      This is also noticeable among rustaceans, otherwise ergonomics for all the .clone() and related machinery, wouldn't be part of the 2026 roadmap.

      • quotemstr 39 minutes ago
        If you want automated resource management, automate it. I'm really not convinced that Koka-style effects-for-everything are a win relative to just passing objects that own resources through parameters so they have actual values and explicit lifetimes.
  • swiftcoder 5 hours ago
    This is a very neat proof of concept that the problem is solvable entirely in safe rust. Obviously the ergonomics suffer, but its an interesting datapoint, and one can hope that future rust developments will mitigate some of the papercuts
    • pjmlp 2 hours ago
      Given your nick, one of the points of 2026 roadmap is exactly trying to make Rust more Swift like, or any other language with RC as automatic resource mechanism for that matter, removing the .clone() pain.

      Or the experiements Niko Matsakis is doing with Dada.

      • swiftcoder 19 minutes ago
        > Given your nick

        Weirdly, I picked this screen name about a decade before Swift the language (and several years before Swift the singer) debuted

  • the-smug-one 6 hours ago
    It's quite unfortunate that traced references has to be wrapped in Gc<>, as this means that your types are bound to a GC allocator (right? Maybe I'm wrong!). It also means that trying out a GC is a pain, as you're stuck first doing the rewrite of your types. The necessity of Trace is another burden, but probably an unavoidable one.

    In this example, you wrap Gc types in Option, I think that having the Gc type be nullable instead would be an interesting experiment. Having to introduce a lot of places that branch both puts more into the instruction cache, and adds more places that the branch predictor has to track. Besides, you can always add in missing checks if you know that you have a sparse subgraph somewhere. Total potential micro optimization, but it's a bit of fun :-).

    I also like how this shows how freelists are a smidge less efficient in safe Rust, as compared to unsafe Rust. In this solution, we have to encode the tag for the discriminated union, this is unnecessary! The unoccupied slots forms its own separate list, and so you know that you will always have unoccupied slots as long as you trace along that path. I assume that that will add up to the maximum alignment of bytes, as arrays need to be well-aligned? So, probably 8 extra bytes per element (you're storing stuff that probably references other stuff).

    • veddan 5 hours ago
      I think it should be possible to get rid of the Option tag without introducing any unsafe code by changing index in Gc from u32 to std::num::NonZero<u32>.
      • jagged-chisel 2 hours ago
        An index of 0 is valid if the collection has any content. This doesn’t solve an out-of-bounds issue with the index (i.e. an index that’s too high)
  • mayhemducks 1 hour ago
    I really like rust because it does NOT have garbage collection. Can someone smarter than me help me understand the benefits of having GC in rust specifically? Does it enable things that are more difficult in "non GC" rust?
    • ameliaquining 17 minutes ago
      To give one trivial example, if you want to write an interpreter for a garbage-collected language in Rust, you need some kind of garbage-collection facility. You could in theory do it C-style by just using raw mostly-untyped pointers everywhere, but this defeats most of the benefit of Rust over C, so you might instead prefer to encapsulate the GC into its own library, so that you can use regular Rust idioms in all the parts of the code that aren't specifically about GC.

      More generally, there are various situations where garbage collection is effectively a requirement: namely, when you've got a mutable graph where anything can point to anything else, where some nodes are root nodes and others are not, and so it's possible for cycles of unreachable nodes to occur and you don't want this to result in memory leaks.

      You could in theory imagine a language like Rust where garbage collection was integrated more deeply on a syntactic level, such that you might sometimes use it for convenience and not just where it's a requirement (and Rust in fact worked like this for a while pre-1.0), but the way things currently work, integrating a garbage-collection library basically always makes your code more unwieldy and you only do it if you have to.

    • Arch485 1 hour ago
      I've never really had the urge to use GC in Rust, but if I were to speculate, I'd say easier cyclic references would be one benefit. And depending on the specific GC implementation, you can probably get around many of Rust's ownership rules because Gc<T> pointers are usually `Copy`, so you can pass things around everywhere and not think about references/ownership as much.
      • mayhemducks 58 minutes ago
        Okay I could see that - like implementing linked lists would be easier yeah?

        I just feel like not having GC is sort of a deliberate, core design choice for the language. Having strict ownership rules and being forced to think about references feels like a feature not a bug you know? Adding GC feels analogous to the "++" in C++ to me.

        Not that I have anything against the efforts people are putting into it though - I'm genuinely curious about what it lets me do better/faster within rust.

    • quotemstr 38 minutes ago
      Why do you like managing your own memory exactly? Modern GCs are quite good, so the domain in which you can beat their performance is narrow and will continue getting narrower as time goes on.
  • foota 7 hours ago
    I found this while looking for a solution for more easily removing some unsafe code from a library that does a lot of C FFI. I didn't end up going with it though, for now I'm taking an approach of mapping valid pointers that I return to the caller and then validating that pointers passed to my library functions are in that valid mapping (and then also using that valid mapping to contain some additional information that doesn't fit in the ABI of the structs that the pointers are for that I use to safely do validation. So e.g., I can store the range of some other valid member pointers as a normal safe rust reference and then index into it with member pointers on the struct, completely avoiding unsafe code despite having this FFI boundary (obviously the FFI boundary itself is still unsafe, but I can take this ugly C struct with a bunch of raw pointers and handle it safely)).
  • rurban 4 hours ago
    Oh oh, who would have thought. A memory-safe rust at last. With no unsafe allowed, even type safe. Unless you forget about their type bugs: https://github.com/Speykious/cve-rs.

    So maybe eliminate type and concurrency unsafeties also then in the next decades or so.

    • bayesnet 3 hours ago
      The existence of a soundness bug in the typechecker doesn’t refute the value of soundness as a language design contract.

      If anything it’s the opposite: issues demonstrated by cve-rs are _language bugs_ and are _fixable_ in principle. “Safe Rust should be memory-safe” is a well-defined, falsifiable contract that the compiler can be measured against. Meanwhile memory unsafety is a feature of the semantics of C++ and so it would be absurd to file a bug against gcc complaining that it compiled your faulty code.

      • rurban 2 hours ago
        The language design contract is unsafe by default. In memory, types and concurrency. What are you talking about? There are unsafe blocks all over the stdlib. And concurrency safety would need to get rid of their blocking IO, which they haven't even acknowledged.
        • quotemstr 37 minutes ago
          > There are unsafe blocks all over the stdlib

          Physics is unsafe. Something, somewhere needs to provide the safe core.

          > And concurrency safety would need to get rid of their blocking IO, which they haven't even acknowledged.

          Is your position that blocking IO can't be compatible with concurrency safety? That's a strange claim. Can you explain?

          • rurban 2 minutes ago
            Sure, but then they shout all over how safe they are. They got rid of the safeties pretty late, when they ripped out their GC, but kept their false promises all over.

            No, that's common knowledge. I fixed concurrency safety by forbidding blocking IO. Others also. Maybe there are other ways, but never heard of other ways.

    • pjmlp 2 hours ago
      It is called OCaml, for those that want it.
    • marcosscriven 32 minutes ago
      I see you’ve been downvoted, but honestly this is news to me.

      I see that repo is two years old - are there flaws in Rust that aren’t edge cases that would make it not memory safe?

      • rurban 5 minutes ago
        Sure, besides those bugs, read the specs. unsafe blocks. Loud and clear. worse than in Java where the unsafeties were just in a hidden sun class.