Live data from Hacker News

Garbage collection for Rust: The finalizer frontier

soft-dev.org

171–180 of 184 posts

Re: Garbage collection for Rust: The finalizer frontier

#171
post #44

> Having acknowledged that pointers can be 'disguised' as integers, it is then inevitable that Alloy must be a conservative GC C# / dotnet don't have this issue. The few times I've needed a raw pointer to an object, first I had to pin it, and then I had to make sure that I kept a live reference to the object while native code had its pointer. This is "easier done than said" because most of the time it's passing strin…

A Gc that can't give you a pointer inside seems almost unusable in the context of Rust. Pointers are not a narrow use case; references are pointers. Rust APIs are largely built around references. If you were to put a Vec (dynamic array) into a pointerless Gc , you would be almost entirely unable to access its contents. The only way to access it would be swap it with an empty Vec, access it, then swap it back a-la Cel…

You miss the point: I'm referring to cases where you pass pointers from one language into another. In that case, because GC is opt-in, it's the wrong approach for managing whatever you're passing into the non-Rust language.

In your case, do you need to get a pointer to a GC and use it within Rust? I haven't worked with Rust at that level yet, so perhaps I'm ignorant of a more common use case.

Re: Garbage collection for Rust: The finalizer frontier

#172
post #125

Earlier quoted context omitted.

Hi -- I'm the one who presented the talk -- honored! I'm curious how you got to "async Rust needs a [tracing] garbage collector" in particular. While it's true that a lot of the issues here are downstream of futures being passive (which in turn is downstream of wanting async to work on embedded), I'm not sure active futures need a tracing GC. Seems to me like Arc or even a borrow-based approach would work, as long as…

My comment is quite general. The difficulties with async/await seem to me to be with the fact that code execution starts and stops using "mysterious magic", and it is very hard for the compiler to know what is in, and what is out, of scope. I am by no means an expert on async/await, but I have programmed asynchronously for decades. I tried using async/await in Rust, Typescript and Dart. In Typescript and Dart I just…

Thank you for the kind words and the thoughtful response.

I'm deeply sympathetic to your viewpoint, and some days I certainly feel like Rust is creaking under its own weight. Why does your typical backend web service need all this complexity with borrows and lifetimes and manual memory management?

But allow me to present the other side of the argument. My background is in systems-level developer tools, and Rust has a combination of things that no other programming environment has:

* & and &mut, which enforce a rigorous separation between mutable and immutable state. I think this is the single most important feature of Rust, and the closest analog to this in other environments is purely functional languages like Haskell

* enums with data + exhaustive pattern matching; the latter is something even Haskell lacks

* high-level idiomatic code that performs like low-level code (e.g. iterators): Rust achieves this through an extraordinary combination of monomorphizing and inlining

* working in memory-constrained environments: tracing GC tends to have significant memory overhead, and I've worked in server environments where a big limiting factor was the amount of DRAM being produced globally

* good polymorphism: I think OOP is a suboptimal paradigm that breaks under day-to-day development stress. I've written about it at https://news.ycombinator.com/item?id=42512629

* fast startup times: this is a requirement for command-line tools people use hundreds of times a day—I spent many years working on Mercurial where Python's slow startup time was a very common complaint

* first-class support for using native OS calls directly; many higher-level languages like Java abstract away the details, so things like signal handling are hard to hook into

* first-class Windows support: again, non-negotiable for many developer tools, since the plurality of developers are on Windows

* and last but not least, a great dependency ecosystem, which ties into all of the above points: & and &mut mean that some transitive dependency three levels down won't suddenly alter the list you pass in, idiomatic performance means that perf regressions are rare, first-class Windows support means most dependencies just work on Windows, and so on

Is it possible to have an application-level/GCd/managed language that meets most or all of these requirements? Certainly. Does such an application-level language exist today? No, and there's nothing on the horizon either (Haskell has its heart in the right place, but is missing many of the more practical features here).

Rust isn't a great application-level language, but it's the best application-level language. And given how high the barrier tends to be for a new language to reach adoption, I'll probably be retired long before something like that shows up.

And yeah, async really is quite confusing in so many ways, and it's really unfortunate that this situation has seen no improvements in so many years. And yet, through its characteristics combined with the other things listed here, it enables developers to solve real problems that are completely infeasible in any other language.

So I keep trying to make Rust better :)

Re: Garbage collection for Rust: The finalizer frontier

#173
post #5

Before making criticisms that Garbage Collection "defeats the point" of Rust, it's important to consider that Rust has many other strengths: - Rust has no overhead from a "framework" - Rust programs start up quickly - The rust ecosystem makes it very easy to compile a command-line tool without lots of fluff - The strict nature of the language helps guide the programmer to write bug-free code. In short: There's a lot…

Aren't Rust programs still considerably larger than their C equivalent because everything is statically linked? It's kind of hard to see that as an advantage.

Yes, all Rust libraries depended on are statically compiled into the final binary. One one hand, it makes binary size much larger, on the other, it makes it much easier to build an application that will "just work" without too much fuss.

In my personal projects with Rust, this ends up being very nice because it makes packaging easier. However, I've never been in a situation where binary size matters like in the embedded space, for example.

Rust isn't the only language with this approach, Go is another.

Re: Garbage collection for Rust: The finalizer frontier

#174

Earlier quoted context omitted.

Aren't Rust programs still considerably larger than their C equivalent because everything is statically linked? It's kind of hard to see that as an advantage.

No. They may be larger because they are doing more work, depends on the program. But no they don’t statically compile everything.

Static compilation and static linking are two separate things - however, Rust is both statically compiled and (usually) uses static linking of dependency libraries.

Re: Garbage collection for Rust: The finalizer frontier

#175
post #125

Earlier quoted context omitted.

My comment is quite general. The difficulties with async/await seem to me to be with the fact that code execution starts and stops using "mysterious magic", and it is very hard for the compiler to know what is in, and what is out, of scope. I am by no means an expert on async/await, but I have programmed asynchronously for decades. I tried using async/await in Rust, Typescript and Dart. In Typescript and Dart I just…

Thank you for the kind words and the thoughtful response. I'm deeply sympathetic to your viewpoint, and some days I certainly feel like Rust is creaking under its own weight. Why does your typical backend web service need all this complexity with borrows and lifetimes and manual memory management? But allow me to present the other side of the argument. My background is in systems-level developer tools, and Rust has a…

> So I keep trying to make Rust better :)

Good.

I am unfamiliar but I think Go meets most of your requirements. Except of course: "working in memory-constrained environments: tracing GC tends to have significant memory overhead". Go has a garbage collector. The Go fans I know laugh in my face about my concerns with garbage collection resource use (especially GC pauses), very fast they say, very good. Mēh. Whatever, Go has been a success in the "developer tools" sector. AFAICT more successful than Rust

Does the embedded world need or want async/await? Is it worth paying the price of extreme complexity in many not so trivial use cases? Have many embedded developers asked for it? I expect not

My strong feeling is that async/await is making easy things easier and many common things harder. A managed runtime would improve the experience a lot - but it would not be the Rust we know. It would be mostly better.

I would not be interested. My interest in Rust is because I like control. I cannot make a business case for any use of Rust except in the places where C and C++ (my first loves) made sense, and that was (is) a very small sector in application programming.

Re: Garbage collection for Rust: The finalizer frontier

#176
post #175

Earlier quoted context omitted.

Thank you for the kind words and the thoughtful response. I'm deeply sympathetic to your viewpoint, and some days I certainly feel like Rust is creaking under its own weight. Why does your typical backend web service need all this complexity with borrows and lifetimes and manual memory management? But allow me to present the other side of the argument. My background is in systems-level developer tools, and Rust has a…

> So I keep trying to make Rust better :) Good. I am unfamiliar but I think Go meets most of your requirements. Except of course: "working in memory-constrained environments: tracing GC tends to have significant memory overhead". Go has a garbage collector. The Go fans I know laugh in my face about my concerns with garbage collection resource use (especially GC pauses), very fast they say, very good. Mēh. Whatever, G…

> I am unfamiliar but I think Go meets most of your requirements.

Go definitely meets many of the requirements here such as fast startup time, but it (like every other imperative language that's not Rust) fails at the & and &mut separation which I've come to regard as the most fundamental requirement of all. Go also doesn't have enums with data and exhaustive pattern matching, and its Windows support is also a bit dodgy -- see things like https://pkg.go.dev/os#Chmod where they try to emulate Unix chmod on Windows. When writing Windows-specific code I want to use Windows idioms, not a Unix emulation layer.

> Does the embedded world need or want async/await?

There is definitely a case to be made that async should have just made futures active and foregone embedded. But people on embedded do use async, such as https://www.reddit.com/r/rust/comments/1nx4df1/comment/nhllr... and https://lib.rs/crates/lilos by my coworker Cliff Biffle (which I understand is now being used at a big tech company).

Re: Garbage collection for Rust: The finalizer frontier

#177
post #117

Earlier quoted context omitted.

> This sounds more like "this is what I like in rust" than "features any modern language should have" though Good build tooling has been around since 2004, and all of the rest of those features have been around since the late 1970s. There's really no excuse for a language not having all of them.

Every language should have haskell level pattern matching?

Yes.

Re: Garbage collection for Rust: The finalizer frontier

#178

Earlier quoted context omitted.

I recall that Mercurial was really fighting their Python test harness. It essentially would startup a new Python process for each test. At 10ms per, it added up to something significant, given their volume of work to cover something as complicated as SCM.

10ms? Did they have like 100k tests?

Found a 2014 thread where 10-18% of the test harness time was spent booting the interpreter for the 13,000 required instances. The deeper thread was showing some 500-700 seconds of test time was just the interpreter overhead. The original point of the article was how much worse the overhead was in Python3 vs Python2.

https://mail.python.org/pipermail/python-dev/2014-May/134528...

Re: Garbage collection for Rust: The finalizer frontier

#179
post #159
post #113

Earlier quoted context omitted.

30ms is pretty close to noticeable for anything that responds to user input. 30ms startup + 20-70ms processing would probably bump you into the noticeable latency range.

People play midi keyboards with 30 ms latency.

Yeah I don’t think 30ms is very noticeable, but say you have a cli tool with other 20-70ms to bump you up to 50-100ms your tool will have noticeable latency. Death by a thousand cuts.

Re: Garbage collection for Rust: The finalizer frontier

#180

Earlier quoted context omitted.

10ms? Did they have like 100k tests?

Found a 2014 thread where 10-18% of the test harness time was spent booting the interpreter for the 13,000 required instances. The deeper thread was showing some 500-700 seconds of test time was just the interpreter overhead. The original point of the article was how much worse the overhead was in Python3 vs Python2. https://mail.python.org/pipermail/python-dev/2014-May/134528...

That's a lot more extreme than 10ms and yea I get your point better now
Post reply on HN