31 ms·
Removing garbage collection from the Rust language (2013)
- unsolved73 3y agoOne of the biggest mistake, in my opinion. Especially with async which complicates lifetimes a lot.
- dystroy 3y agoRust noob here. Can you please explain how removing '~' and '@' by moving the GC to a library makes async harder ?
- baq 3y agoit's not the things that were removed, it's the things you have to add to the source now to make it work within the limits of the borrow checker. in the simplest case, you'd add Arc<..> everywhere @ used to be.
- arghwhat 3y agoRather than those operators and how GC is done, I think the key aspect is how much easier async is in other languages that have easy automatic memory manage without ownership through garbage collection. Go and JavaScript/Dart are good examples. But such models would also take away everything that makes Rust... Rust.
- yccs27 3y agoI suspect GP only read the title and not the article. A Java-style GC might make async code easier, but that never existed in Rust.
- BenoitP 3y agoLifetimes complicated. Having a proof of them at compile time is difficult. You can't prove everything for starters. A lot of patterns are just a no-go. Why not defer that to the runtime, and just observe which variables stick around (that's GC) IO complicated. The cycle of doing code then waiting for IO is wasteful (sequentially you waste millions of CPU cycles waiting for the network to answer back). To max out usage of your hardware resources you could just aggregate IO requests with your compiler. Switching back and forth between code that uses IO, as IO request come back (that's async) Problem is: switching back and forth between code that uses IO is recklessly hard wrt coming up with a proof of the lifetimes of the variables. And a language/runtime _needs_ to have the trifecta of compiler/GC-or-memory-management/memory-model coherent and within the runtime. compiler/GC-or-memory-management: the GC-or-memory-management needs to know who writes, who owns, who reads GC-or-memory-management/memory-model: you need to know when and how you can read your writes, what are the rules memory-model/compiler: you'll be managing memory barriers so that you can cram together sequences of writes that are compatible, for maximal performance This trifecta dependence is foundation to a language/runtime, and a change to one affects the others quite deeply. Changing the compiler (bringing async here) affects the other ends and you can't do that when GC-or-memory-management is all over the place (as a lib, or god forbid in user hands) I'm afraid async is just something unaffordable for a language that wants to be that close to the metal. And even then, async is just a bandaid for a costly threading IO model. ---- Come over to the dark side of Erlang, Go, and Java. We have small threads now. You can just block like there is no tomorrow, and the runtime will have a cheap back and forth. You can just forget about the lifetimes, as the GC will sweep after you (and concurrently, outside of the critical allocation path). Forget it all my friend. Java is love, Java is life.
- nu11ptr 3y agoThey wanted a systems language. A GC would be very appropriate for much of the code I write, but would not have been for an OS kernel. Green threads removed as well. I admit the GC version with green threads I would have preferred, but again, not appropriate for the domain they wanted. I still want my halfway between Go and Rust language.
- ynik 3y agoA GC-free systems language isn't just for OS kernels. Rust's main use case was to replace C++ components in firefox. This wouldn't have been possible with a language that brings along its own GC, as Firefox already has a JS GC. Multiple garbage collectors in the same process are a quick way to madness, especially if you have reference cycles stretching across multiple GC heaps. This also comes up when writing Python extension modules, base libraries that are meant to be usable across languages, etc... This is part of why Rust is so successful -- it's the first real alternative for this space since C++ came along. For most application development, it's better to use a garbage collected language. But in the application space there is a much bigger choice of languages already available, Rust wouldn't have been a big deal over there.
- tikkabhuna 3y agoI do wonder why there hasn't been more exploration in a series of languages that have a very similar style and toolchain but have different audiences. It would be great to have Rust, Rust with a GC, and then some sort of interpreted language that has a similar syntax. When jumping between languages I feel like half the battle is overcoming muscle memory.
- 0cf8612b2e1e 3y agoThis is my dream. An interpreted language, implemented in Rust which essentially boxes all data and can do message passing to the host language. This would then give a somewhat plausible upgrade path to port the interpreted code into Rust bit by bit as required. The interpreted language even be slower than Python, so long as the escape hatch to Rust was simple and safe enough to implement the interfaces.
- nercury 3y agoWith GC rust would have been just another slightly different language.
- Shorel 3y agoThen you can use D lang.
- api 3y agoRust is a language for writing the GC, runtime, OS kernel, etc.
- pjmlp 3y agoAnd? Plenty of GC enabled system programming languages have achieved similar feats, with bigger outcome than Rust has managed to on the desktop space, e.g. Xerox Workstations, across Smalltalk, Intelisp-D and Mesa/Cedar. Redox is still not as feature rich as Mesa/Cedar was on the Dorado in 1981. https://www.youtube.com/watch?v=z_dt7NG38V4 https://www.youtube.com/watch?v=z_dt7NG38V4 By the way Go, D, Eiffel, Nim, Common Lisp, Scheme, some JVM implementations are bootstrapped, meta-circular, with their own GC implemented on them.
- qalmakka 3y agoA GC would have made Rust yet another Dlang, which is pointless because Dlang has existed for a way longer time.
- silon42 3y agoOr more realistically, another JVM language. I actually wouldn't mind a subset of Rust that targets the JVM.
- raverbashing 3y agoSo why Dlang has not gotten as popular as rust or go?
- nickpp 3y agoLack of a big corporate backer is my best guess.
- qalmakka 3y agoa. it never had a real corporate backer, until it was too late (and Rust already stole all of its mindshare) b. It had a garbage collector, which meant that realistically it could not replace C++. Or rather, it could but you basically had two different Dlangs - one with GC and classes, and one without. It was arguably not necessary, because people already had GC languages that were fast enough and worked for their needs, and those who needed speed were better served by C++, which arguably isn't that bad of a language if you know how to use it. Rust is arguably the first real contender to C++'s reign because it really brings to the table features you'd be a fool to pass on. D was nice, but it was not worth the switch. Eliminating whole classes of bugs instead is.
- eftychis 3y agoI (also like sibling comments) respectfully disagree. Rust is aimed and focused as a safe C or a sane C++ substitute, and is meant to intermingle with both. It is not an application "high" level language. You can use it as such, which is great. For anything you would use C or C++ you can use Rust instead. As a cryptographer I find that great. Regardless of all the lack of latency or other control -- beyond fine tuning -- a garbage collected language makes critical memory choices we want to make instead. There are times we want to swap or use our own memory allocator, never mind having to add a garbage collector in the mix. (There is a good number of languages that scratch that itch, and you can likely link and use your C/Rust code with them.) As far as async: also respectfully disagree. Async is sugar for here is a Future<..>. If you want to poll it locally you can. You can scope it also. If you want to use a cross thread work stealing algorithm you can. But you need like memory management to consciously make these design decisions. This is similarly why a lot of things are not built in in C.
- j1elo 3y agoI heard this brilliant summary in a video from ThePrimeagen: In Rust, lifetimes color your types, like async colors your functions. It is a great condensed summary of what makes lifetimes a great difficulty of async Rust. It's a language that has the function coloring that is typically introduced by async (likewise in JavaScript), and on top of that the typesystem itself gets colored by lifetime annotations. You can have a well written and working program... then due to some new need or refactoring, wanting to add a 'static somewhere will cause it all to break down. It's part of the language, nothing bad with that. But it is an extra layer of difficulty that needs to be mastered. To me it shows that Rust might only be the initial step towards future programming languages where this kind of issue doesn't lean so much on developer knowledge.
- rcarr 3y agoCan you post a link to this video? Sounds interesting
- justincredible 3y ago[dead]
- orf 3y agoRust has had an interesting and probably pretty unique story, moving from a GC’d language with a runtime + green threads[1] to what it is today. They are treading a line that is uniquely difficult to tread, and I think it’s mostly working. Async is still a bit of a mess but it seems that’s because it’s inherent to the constraints they had to impose on themselves. It’s kind of cool that I can use Async stuff in embedded devices[1] and a web app, even if I do get frustrated with mind-numbing Async issues from time to time. 1. https://github.com/rust-lang/rfcs/pull/230 https://github.com/rust-lang/rfcs/pull/230 2. https://embassy.dev/ https://embassy.dev/
- rcarr 3y agoFor anyone interested there was a big discussion on async in rust a few days ago. Rust is on todo list to learn but I found reading some of these comments quite interesting: https://news.ycombinator.com/item?id=37435515 https://news.ycombinator.com/item?id=37435515
- mplanchard 3y agoNote also this rebuttal: https://news.ycombinator.com/item?id=37448460 https://news.ycombinator.com/item?id=37448460 As someone who works with async rust professionally, I wouldn’t let takes like the one you posted dissuade you. My personal opinion is that async rust is easier to work with than in most other languages because of the extra concurrency guarantees that rust gives you. There are some rough edges, but not nearly as many as the link you posted suggests.
- littlestymaar 3y agoThis exactly. Sure Async Rust requires you to learn a few new things, but the blog post is mostly a rant from someone not very familiar with the topic (like what you'd expect from something called “<X> is a bad language” TBH).
- rcarr 3y agoI wasn't, I actually didn't even read the attached article only the HN comments who seemed to mainly disagree with the article and mentioned quite a lot about the different approaches to async in Rust. I really want to learn it but prioritising up-skilling my DevOps capabilities at the minute so it will have to be next year.
- raincole 3y agoI think it's quite unfortunate that there isn't a language with 1) Rust's type system or something as expressive 2) C#-level performance 3) GC by default 4) Ecosystem that is as big as Rust The closest thing seems to be TypeScript (weirdly).
- chris_nielsen 3y agoNot trying to be cheeky, but why not c#? Has pts 2, 3 and 4. For pt 1, what in Rusts type system are you looking for?
- jen20 3y agoSum types, which can only be approximated in C# via records, and no exceptions, which is even a problem for F#.
- tazjin 3y agoI don't know C#, so maybe it has these, but it's unlikely: - absence of null pointers - proper sum types which can be statically checked for exhaustiveness - statically controlled mutability (yes, borrow-checking is still useful if you have a GC!) Also no exceptions, but that's not a type system feature.
- seabrookmx 3y agoC# calls the first one "nullable reference types." When that build option is enabled, all types are non-nullable by default, and you can make them optionally nullable by declaring them like "MyClass? cls = null;" The compiler will ensure you check for null before de-referencing a nullable type.
- tazjin 3y agoHow does this interact with third-party dependencies you use? In my experience, most gradual typing things break down at that boundary.
- vaylian 3y agoAnd only 2 years later Rust 1.0 was released with a borrow checker (which is not mentioned in the blog post). I think one of the reasons why Rust turned out to be so well-designed is that Rust has a very open development approach where people with many different experiences can share their wisdom. Many other languages follow the design of a few people, but Rust is really a language of the internet community.
- faitswulff 3y ago> I think one of the reasons why Rust turned out to be so well-designed is that Rust has a very open development approach where people with many different experiences can share their wisdom. Probably also why Rust has such highly publicized drama, as well. The drama is out in the open, too.
- mhh__ 3y ago[flagged]
- brabel 3y agoI don't agree. Before Rust 1.0 the community was really, really tiny. I don't have numbers but it was really a few people discussing the design issues... it was not like now where you literally have thousands of people with different incentives trying to force their views on things, which makes development go much slower than in the pre-1.0 days. I think the lesson is that, as with any software, having an open discussion between people who are on the same page about things and have similar incentives (with room for disagreements, as the initial author of Rust had plenty of) is greatly beneficial, without a doubt... but once you start getting people with polar opposite views on things, each backed by a substantial faction behind them, things start getting messy. I'm not saying this has happened in Rust, just that it's not a case the more people, the merrier.
- lagniappe 3y agoI'm sure it'd be different for everyone reading this, but for me this story reinforces my hunch that the BDFL model moves faster and satisfies more people, in the sense that its hard to design by committee and harder to satisfy everyone.
- jxf 3y agoEarly Rust was really incomprehensible to me, and it's unquestionably better than it once was from an ergonomics and ecosystem perspective. The ~ and @ sigils everywhere were verging on Perl!
- cmrdporcupine 3y agoI actually think removing ~ was a mistake. a) A lot of code ends up littered with Box anyways, which frankly isn't any more readable since "Box" doesn't tell you anything until you already know what it is and once you do it's just verbosity. b) As I understand it, Box gets "special treatment" by the compiler/type system, so pretending it's just a pure standard library component is a bit obfuscatory c) Heap allocation and heap pointers are first class citizens in other languages, why wouldn't they be so in Rust?
- veber-alex 3y ago> b) As I understand it, Box gets "special treatment" by the compiler/type system, so pretending it's just a pure standard library component is a bit obfuscatory There is a strong desire to stop that and have Box be a normal std type, the main thing that is blocking this at the moment is that Box has special deref magic that is not possible to implement with surface level rust syntax (even with nightly features).
- qalmakka 3y agoThe fact they've managed to bring safety to the masses without a GC is arguably the #1 reason for Rust's success. This has been a good move.
- gwbas1c 3y ago> The fact they've managed to bring safety to the masses without a GC is arguably the #1 reason for Rust's success. This has been a good move. That's an understatement. Rust doesn't require a framework / runtime. Unlike NodeJS, Python, Java, C#, ect; when you ship a Rust program, it has no external requirements. More important: Because Rust can create libraries that adhere to the C calling convention, you can create libraries that you can call from NodeJS, Python, Java, C#, ect. The fact that those systems have a heavyweight runtime (with GC) makes it very hard to create a library in one environment and call it from the other. I do think there's room for an "R2" that is semantically identical, but designed to be easier to understand. Probably the biggest room for improvement is using generics for things like RC, ARC, Mutex. I'd rather use something like keywords; and leave generics for user-defined types. This way, when trying to understand what something "is," the "how the memory is tracked" is semantically different from "what the struct is." (Even though under the hood they are the same thing.)
- thinkharderdev 3y ago> using generics for things like RC, ARC There is an unstable feature for "box syntax" which both allows you to construct a `Box<T>` as let foo = box a (instead of let foo = Box::new(a)) but also to use box as a keyword in pattern matches to deref the box automatically. So struct Foo { value: Box<Bar> }; let Foo { value: box Bar } (in which case value is bound to a &Bar) which was really nice. It got subsumed into a more generic "deref patterns" project which doesn't seem to be going anywhere but I hope it does because it makes the language much more ergonomic IMO.
- SkiFire13 3y agoThe `box` syntax to create `Box`es has been removed because it was broken. The initial idea was to have it initialize the value directly in the heap, but that never worked for function calls. The `box` pattern instead remained as it was still useful to have (really unfortunate for the perma-unstable status though).
- frankreyes 3y agoRust just took C++ std::unique and std::shared ptr and made those integrated directly in the language, and the only option for allocation. Which is awesome. It would be nice to see if we can have a sub set of C++ that forces us to only use std::make_unique or std::make_shared calls.
- UncleMeat 3y agoYou can already write a very very very simple linter that bans use of the "new" keyword. Rust did quite a bit more to make this ergonomic than just force you to use smart pointers.
- proto_lambda 3y ago> Rust just took C++ std::unique and std::shared ptr and made those integrated directly in the language, and the only option for allocation Not really. Both Box and Rc/Arc are first and foremost library features implemented using the equivalent of malloc() and free(). Box is a bit special due to its deref semantics, but other than that, there's nothing stopping you from implementing them or something else yourself.
- frankreyes 3y agoThanks, never wrote Rust so I'm just guessing. What else there is, besides static type checks? Is there a runtime side too?
- proto_lambda 3y agoThere is no runtime (other than init/exit handling). The main thing that provides memory safety without a GC is the borrow checker, which is a language feature and independent of the smart pointer types in the standard library.
- chrismorgan 3y agoIt’s worth noting, given the aspirational conclusion, that @T managed pointers were actually equivalent to Rc<T>, since they were only ever implemented with reference counting without cycle collection. (This would have changed had they stayed in the language, but winds changed instead.) The standard library doesn’t ship tracing GC, and it’s still not altogether clear how it would be best to do it. https://manishearth.github.io/blog/2021/04/05/a-tour-of-safe-tracing-gc-designs-in-rust/ https://manishearth.github.io/blog/2021/04/05/a-tour-of-safe... is useful further reading. I think it’s fair to say that the “ship tracing GC as part of the standard library” ship has sailed, but power and convenience could still warrant language/standard library features to support it, though I doubt anything will ever happen, or at least in the next decade. The focus of the language shifted and was clarified quite a lot between the time of this article and even Rust 1.0 just under two years later.
- dingi 3y agoI'm pretty sure that Rust is a great language for low level stuff, the domain of C/C++. Try to shoehorn it to do more higher level stuff (i.e: vast majority of software developed today), And you'll be fighting battles with the language at each step. For those use cases, Java, JavaScript, Python et al will reign supreme for many years to come. Most of the time, GC stalls are the least of your problems.
- binary132 3y agocall me crazy, but I found old-style Rust, runtime and all, much more appealing.
- jedisct1 3y agoYou're not alone.
- timeon 3y agoRust has other nice features but I started with Rust not in spite of borrow checker but because of it. Without borrow checker why would one choose Rust? I would choose from large pool of GC-languages.
- fleventynine 3y agoThen choose from one of the countless garbage-collected languages with sum types and a runtime; Rust is successful because it's offering us systems programmers something unique.
- mjw1007 3y agoHere are some notes on the later history of GC in Rust: RFC 256, 2014-09. https://rust-lang.github.io/rfcs/0256-remove-refcounting-gc-of-t.html https://rust-lang.github.io/rfcs/0256-remove-refcounting-gc-... Includes « I (and I think the majority of the Rust core team) still believe that there are use cases that would be well handled by a proper tracing garbage collector. » https://news.ycombinator.com/item?id=8312327 https://news.ycombinator.com/item?id=8312327 A core developer says « I wouldn't be so quick to give up on GC support yet! "We have a plan!" But I don't think we'll have it in for Rust 1.0. And it's true that, even if we never do get it to work in a satisfactory way, the language works just fine without it. » By 2015-04 ("Fearless Concurrency"), "Memory safety without garbage collection." is a "key value proposition" (this isn't quite the same as saying "we never want Garbage Collection", of course). 2016-08 https://manishearth.github.io/blog/2016/08/18/gc-support-in-rust-api-design/ https://manishearth.github.io/blog/2016/08/18/gc-support-in-... « Recently we (Felix, Niko, and I) have been working on getting compiler-level GC support for Rust. » 2018-10 withoutboats has a research garbage collector as a library: https://boats.gitlab.io/blog/post/shifgrethor-i/ https://boats.gitlab.io/blog/post/shifgrethor-i/ The intro post includes « I do not expect we will ever “add GC to Rust” ». 2021 summary of options: https://manishearth.github.io/blog/2021/04/05/a-tour-of-safe-tracing-gc-designs-in-rust/ https://manishearth.github.io/blog/2021/04/05/a-tour-of-safe...
- bunderbunder 3y agoWhat I increasingly want to see is a language where a garbage collector is optional in the main executable, but not (directly) available to library code. Because I want to have a language that I can use to write lean libraries that are available to any language with a C FFI, and that can be linked directly by AOT-compiled languages, without getting into a horrible quagmire of dueling heaps and copying. But I also want to have proper functional and asynchronous programming, and generally just to not have to manually fuss with memory in the higher-level code. Python and C/C++/Rust/Cython/etc extensions kindasorta achieves this, and it's a huge factor in the language's ascendance in scientific computing applications. Game development has a long history of achieving a similar effect by embedding Lua or Lisp. But I think that it might be more pleasant to have it formalized and baked into a single language.
- AndrewDucker 3y agoPossibly Rust needs a GC<> wrapper type, which makes everything it contains garbage collectable. And then you could be bare metal, except when you want to not be.
- zozbot234 3y agoThere are a number of efforts along these lines, the most interesting is probably Samsara https://github.com/chc4/samsara https://github.com/chc4/samsara https://redvice.org/2023/samsara-garbage-collector/ https://redvice.org/2023/samsara-garbage-collector/ which implements a concurrent, thread-safe GC with no global "stop the world" phase.
- deleted 3y ago[deleted]
- yjftsjthsd-h 3y agoI'm reminded of wuffs, which only allows writing libraries and explicitly doesn't support allocateing memory, requiring the calling program to provide memory. It seemed like a nice separation of concerns in my non-expert view. (And then wuffs compiles to C, which is nice for interoperability)
- Alifatisk 3y agoWould adding the GC back make the syntax easier to read and remove all those special characters like the way lifetime is handled?
- steveklabnik 3y agoEven if in theory it would, Rust's commitment to backwards compatibility would mean that those things could not be removed. You're asking for a different language.
- yencabulator 3y ago> remove garbage collection from the core language and relegate it to the standard library, with a minimal set of language hooks in place to allow for flexible, pluggable automatic memory management. They did part one, but not part two...
- gabereiser 3y ago>"The sigils make the code unfamiliar before the concepts are learned. Unlike the rest of the punctuation in Rust, ~ and @ are not part of the standard repertoire of punctuation in C-like languages, and as a result the language can seem intimidating." It's still intimidating with lifetimes and Arc<Box<Rc>> like idioms. Still, it's blazingly fast (tm). I wonder what Rust would be like if the GC was kept in like in Go.
- kaba0 3y ago> I wonder what Rust would be like if the GC was kept in like in Go. It would be one of the litany of managed languages that doesn’t significantly differ in anything from each other, and we would have no reason to be hyped about.
- gabereiser 3y agoHype is subjective but I do welcome a safer C++.
- dang 3y agoDiscussed at the time: Removing garbage collection from the Rust language - https://news.ycombinator.com/item?id=5811854 https://news.ycombinator.com/item?id=5811854 - June 2013 (130 comments)