Remix.run Logo
Aurornis 3 days ago

> thus effectively switching to automatic garbage collection

Arc isn't really garbage collection. It's like a reference counted smart pointer like C++ has shared_ptr.

If you drop an Arc and it's the last reference to the underlying object, it gets dropped deterministically.

Garbage collection generally refers to more complex systems that periodically identify and free unused objects in a less deterministic manner.

ninkendo 3 days ago | parent | next [-]

Also importantly, an Arc<T> can be passed to anything expecting a &T, so you’re not necessarily bumping refcounts all over the place when using an Arc. If you only store it in one place, it’s basically equivalent to any other boxed pointer.

Arnavion 3 days ago | parent | prev | next [-]

>Garbage collection generally refers to more complex systems that periodically identify and free unused objects in a less deterministic manner.

No, this is a subset of garbage collection called tracing garbage collection. "Garbage collection" absolutely includes refcounting.

simonask 3 days ago | parent [-]

There’s just no good reason to conflate the two. Rust’s Arc and C++’s std::shared_ptr do not reclaim reference cycles, so you can call it “garbage collection” if you want, but the colloquial understanding is way more useful.

pjmlp 2 days ago | parent [-]

The coloquial term is like people arguing about coaching a footbal team without making it into the field.

Chapter 5, https://gchandbook.org/contents.html

Other CS quality references can be provided with similar table of contents.

hansvm 3 days ago | parent | prev | next [-]

That's fair. It's not really a good pattern though. You get all the runtime overhead of object-soup allocation patterns, syntactic noise making it harder to read than even a primitive GC language (including one using ARC by default and implementing deterministic dropping, a pattern most languages grow out of), and the ability to easily leak [0] memory because it's not a fully garbage-collected solution.

As a rough approximation, if you're very heavy-handed with ARC then you probably shouldn't be using rust for that project.

[0] The term "leak" can be a bit hard to pin down, but here I mean something like space which is allocated and which an ordinary developer would prefer to not have allocated.

Aurornis 3 days ago | parent [-]

I agree that using an Arc where it's unnecessary is not good form.

However, I disagree with generalizations that you can judge the quality of code based on whether or not it uses a lot of Arc. You need to understand the architecture and what's being accomplished.

hansvm 3 days ago | parent [-]

> disagree with generalizations that you can judge the quality of code based on whether or not it uses a lot of Arc

That wasn't really my point, but I disagree with your disagreement anyway ;) Yes, you don't want to over-generalize, but Arc has a lot of downsides, doesn't have a lot of upsides, and can usually be relatively easily avoided in lieu of something with a better set of tradeoffs. Heavy use isn't bad in its own right, but it's a strong signal suggestive of code needing some love and attention.

My point though was: If you are going to heavily use Arc, Rust isn't the most ergonomic language for the task, and where for other memory management techniques the value proposition of Rust is more apparent it's a much narrower gap compared to those ergonomic choices if you use Arc a lot. Maybe you have to (or want to) use Rust anyway for some reason, but it's usually a bad choice conditioned on that coding style.

bluGill 3 days ago | parent | prev | next [-]

Reference counting has always been a way to garbage collect. Those who like garbage collection have always looked down on it because it cannot handle circular references and is typically slower than the mark and sweep garbage collectors they prefer.

If you need a referecne counted garbage collector for more than a tiny minotiry of your code, then Rust was probably the wrong choice of language - use something that has a better (mark and sweep) garbage collectors. Rust is good for places where you can almost always find a single owner, and you can use reference counting for the rare exception.

Aurornis 3 days ago | parent [-]

Reference counting can be used as an input to the garbage collector.

However, the difference between Arc and a Garbage Collector is that the Arc does the cleanup at a deterministic point (when the last Arc is dropped) whereas a Garbage Collector is a separate thing that comes along and collects garbage later.

> If you need a referecne counted garbage collector for more than a tiny minotiry of your code

The purpose of Arc isn't to have a garbage collector. It's to provide shared ownership.

There is no reason to avoid Rust if you have an architecture that requires shared ownership of something. These reductionist generalizations are not accurate.

I think a lot of new Rust developers are taught that Arc shouldn't be abused, but they internalize it as "Arc is bad and must be avoided", which isn't true.

bluGill 2 days ago | parent [-]

> whereas a Garbage Collector is a separate thing that comes along and collects garbage later.

That is the most common implementation, but that is still just an implementation detail. Garbage collectors can run deterministically which is what reference counting does.

> There is no reason to avoid Rust if you have an architecture that requires shared ownership of something.

Rust can be used for anything. However the goals are still something good for system programming. Systems programming implies some compromises which makes Rust not as good a choice for other types of programming. Nothing wrong with using it anyway (and often you have a mix and the overhead of multiple languages makes it worth using one even when another would be better for a small part of the problem)

> I think a lot of new Rust developers are taught that Arc shouldn't be abused, but they internalize it as "Arc is bad and must be avoided", which isn't true.

Arc has a place. However most places where you use it a little design work could eliminate the need. If you don't understand what I'm talking about then "Arch is bad and must be avoided" is better than putting Arc everywhere even though that would work and is less effort in the short run (and for non-systems programming it might even be a good design)

nayuki 3 days ago | parent | prev | next [-]

> Arc isn't really garbage collection. It's like a reference counted smart pointer

Reference counting is a valid form of garbage collection. It is arguably the simplest form. https://en.wikipedia.org/wiki/Garbage_collection_(computer_s...

The other forms of GC are tracing followed by either sweeping or copying.

> If you drop an Arc and it's the last reference to the underlying object, it gets dropped deterministically.

Unless you have cycles, in which case the objects are not dropped. And then scanning for cyclic objects almost certainly takes place at a non-deterministic time, or never at all (and the memory is just leaked).

> Garbage collection generally refers to more complex systems that periodically identify and free unused objects in a less deterministic manner.

No. That's like saying "a car is a car; a vehicle is anything other than a car". No, GC encompasses reference counting, and GC can be deterministic or non-deterministic (asynchronous).

jcelerier 3 days ago | parent | prev | next [-]

> Arc isn't really garbage collection. It's like a reference counted smart pointer like C++ has shared_ptr.

In c++ land this is very often called garbage collection too

jandrewrogers 3 days ago | parent | prev [-]

This still raises the question of why Arc is purportedly used so heavily. I've written 100s of kLoC of modern systems C++ and never needed std::shared_ptr.

pjmlp 3 days ago | parent [-]

For the same reason Unreal uses one.

Large scale teams always get pointer ownership wrong.

Project Zero has enough examples.