News for hackers. Stuff that matters.
Re:Removing Garbage Collection from the Rust Language (2013) by dcuthbertson on Monday September 11, 2023 @07:49AM (#37465855)
Excuse my ignorance (I have only just started learning Rust), but why is GC by default desirable? If a programming language can tell when a variable goes out of scope, or its lifetime ends and use that information to automatically release allocated memory, then why is having a garbage collector important? Does Rust (as a result of not having GC) put restrictions on the kind of code you can write, or force one to write code in such a way that it's difficult to reason about?
Re:Removing Garbage Collection from the Rust Language (2013) by nu11ptr on Monday September 11, 2023 @07:53AM (#37465886)
Yes, it has a borrow checker which restricts some valid code and occasionally makes you jump through hoops and write in a different style.

Also, a garbage collector that is state of the art (bump allocation, generational, and compacting) is faster overall typically (throughput-wise, but with less predictable latency) than naïve Rc/Arc all over the place (due to usage of "free list" allocator and counter bumps). That isn't to say blisteringly fast Rust isn't possible to write, and in fact it is pretty easy to write by avoiding Rc/Arc except where necessary and using the stack with the borrow checker, but this entails a writing style that is more "low level" and thus takes a bit more thinking.

Re:Removing Garbage Collection from the Rust Language (2013) by HankB99 on Monday September 11, 2023 @08:23AM (#37466188)
IANAGCE (I am not a GC expert.) I thought there were potential costs to using GS.

1. Interrupting the program to sweep, resulting in unpredictable performance.

2. Possibility that a circularly linked group of variables could be impossible to sweep, resulting in memory leaks.

3. Need to check reference counts (along with bounds checks) that degrade performance.

Lack of GC (and bounds checking) are factors that make C/C++ performant and then lead to the kind of bugs that result in programs that don't do what they're supposed to do (and at worst, result in security vulnerabilities.)

I thought a key goal of Rust was to fix these problems without sacrificing performance.

Re:Removing Garbage Collection from the Rust Language (2013) by nu11ptr on Monday September 11, 2023 @08:59AM (#37466581)
> 1. Interrupting the program to sweep, resulting in unpredictable performance.

See my comment regarding "less predictable latency" (although new advances are making for much more predictable latency - see some of the work done in Java GCs for example)

> 2. Possibility that a circularly linked group of variables could be impossible to sweep, resulting in memory leaks.

That is not possible in a precise tracing collector, only in reference counting (Rc/Arc)

> 3. Need to check reference counts (along with bounds checks) that degrade performance.

I think you are referring to reference counting again. Both Rust and C++ have reference counting types as an add on.

State of the art tracing collectors don't collect/check dead objects, they compact live ones, and often don't use reference counting directly. Most objects die young.

> Lack of GC (and bounds checking) are factors that make C/C++ performant and then lead to the kind of bugs that result in programs that don't do what they're supposed to do (and at worst, result in security vulnerabilities.)

Replace "performant" with "predictable performance"

> I thought a key goal of Rust was to fix these problems without sacrificing performance.

Rust, like C/C++, wants you to be able to predict performance and latency and without the baggage of a runtime. Nothing more than trade offs - neither is better or worse. GCs often do perform better with the trade off of latency predictability, but as always it depends on use case as to what is appropriate. Rust likely made the right choice for its domain.

Re:Removing Garbage Collection from the Rust Language (2013) by kaba0 on Monday September 11, 2023 @12:28PM (#37469665)
What kind of GC do you talk about here? (RC is also a GC algorithm, but you seem to mix some of its shortcomings with that of trading GCs).

1) this is generally true, but many part of this can be done concurrently, and if we want to improve latency at the cost of some throughput than there are low-lat GCs that maximize the pause times (it is basically independent from the heap size), so in practice you have similar interrupts as you would from the OS alone.

2) this is not a problem with tracing GCs, only with refcounting (most well known is Python, ObjC and Swift for this perhaps). You can still leak memory everywhere by e.g. storing them in a huge list forever, though, but that is a much rarer and easy to debug bug.

3) this is again only true for RC, and it is the reason why it is slower than tracing GCs, especially when it is multithreaded and the increment/decrement has to be an atomic operation.

Re:Removing Garbage Collection from the Rust Language (2013) by dcuthbertson on Monday September 11, 2023 @08:16AM (#37466109)
Thanks for that explanation! I'm going to have to dive into Rc/Arc [0]. Reference counting built into the standard library is really interesting. Several years ago I wrote a Windows kernel minifilter and reference counting is used a lot by anything that interacts with the filter manager. RC was very helpful to ensure the minifilter didn't leak memory when it was unloaded.

[0]: https://doc.rust-lang.org/std/sync/struct.Arc.html

Re:Removing Garbage Collection from the Rust Language (2013) by mhh__ on Monday September 11, 2023 @08:26AM (#37466210)
With a GC you can basically write whatever you want with reckless abandon and because it's cleaned up at runtime, it's mostly kosher.

Without a GC (i.e. rust), in order to be able to make guarantees about things that it cannot determine at compile time (this is a mathematical impossibility) it restricts the set of programs you can write.

Re:Removing Garbage Collection from the Rust Language (2013) by Someone on Monday September 11, 2023 @11:42AM (#37468953)
> If a programming language can tell when a variable goes out of scope, or its lifetime ends

Whether a variable goes out of scope is trivial in many languages. The problem is with determining whether the lifetime of a value ends.

For example:

    func foo(items, moreItems) {
        b = new bar()
        if coinflip() {
            items.append(b)
        }
        if coinflip() {
            moreItems.append(b)
        }
        // ‘b’ goes out of scope here, but its value
        // may live on inside ‘items’ and/or moreItems
        // and will have to be destroyed when it’s no
        // longer stored in either.
    }
In general, once you allow for dynamic allocation and references that can be copied (so that multiple objects ‘know’ of the allocated object), it can be very difficult to determine exactly when the last reference to such an object ceases to exist.
Re:Removing Garbage Collection from the Rust Language (2013) by dcuthbertson on Wednesday September 13, 2023 @07:08AM (#37495135)
Yes, I agree that determining the lifetime of a value is the hard part. I wrote "... and use that information to automatically release allocated memory, ..." to imply the language got lifetime detection right.
Re:Removing Garbage Collection from the Rust Language (2013) by kaba0 on Monday September 11, 2023 @12:21PM (#37469562)
> Does Rust (as a result of not having GC) put restrictions on the kind of code you can write

Depending on what you mean by kind: yes. That is, Rust does limit your code’s architecture to a subset that is fine for most things, but not everything.