4 ms·
The thing is that most code has a straightforward, tree-like ownership model. It’s overkill to use a GC for everything. It also sometimes leads to memory bloat.
by vlmutolo 3y ago
The thing is that most code has a straightforward, tree-like ownership model. It’s overkill to use a GC for everything. It also sometimes leads to memory bloat.
What we really need is an ergonomic way to opt into different kinds of memory allocation and management. The borrow checker is great for when you need no extraneous allocation. GCs are great for many linked lists. Bump allocators are great for web template rendering with lots of temporary strings.
- logicprog 3y agoThis is my position as well. Call me a crank, but while a lot of people say that you don't need to go without a garbage collector for most problems, I believe the converse: that there aren't many problems where you actually need a garbage collector (if you have some other way of freeing yourself from having to manually manage your memory and manually avoid use after free and so on). I think once your mind gets adjusted to working without one and within the constraints of the borrow checker, it's really not that much of a drag, and if you really need to do something outside those bounds (or just want to ignore it and hack something together quickly) that's what Gc and Arc are for. And honestly, in general I like the unique intersection of features that Rust offers as a language, totally independent from its performance or the presence or absence of a garbage collector at all. Even if it was garbage collected and about 2x slower, I think I would still prefer it to most of the 40 or so languages that I've tried over the years. It feels like a version of OCaml with a much better standard library and ecosystem, a much better build system, a vastly better and cleaner way of doing parametric polymorphism, and much better metaprogramming facilities in comparison. Not only that, but I genuinely find the constraints of the borrow checker — most especially only allowing either one mutable reference or multiple read-only references at a time — to be a great help in making my code clearer and more straightforward: it essentially helps me reach a lot of the same benefits as pure functional programming (where the data flow of my application is carefully threaded and there is no spooky action at a distance) while still allowing me to have imperative programming and mutation where I need it, by just forcing me to only have one place in my code be able to mutate anything at a given time, to explicitly mark it whenever I'm giving any piece of my code mutable access to anything, and essentially preventing me from having any persistent mutable access to a data structure be held in some other data structure or portion of code that can then continue to mutate it without my explicit permission and knowledge. So why give up the uniquely productive constraints of the borrow checker, which again to reiterate give me 90% of the benefits of pure functional programming with only 50% of the annoyance, and add in all of the unnecessary bloat and non-determinism of a garbage collector, when I have never really found myself to need it? Furthermore, Rust is significantly more performant than even very fast and systems oriented garbage collected languages with their own runtime such as Go or OCaml or Java, which has the added benefit of allowing me to not really have to worry about performance at all beyond picking reasonable algorithms, and sometimes not even then since the language is often fast enough to make brute force feasible, which paradoxically means that when I am programming in rust, this high performance systems language, it often frees me from the burden of having to worry about performance like I would in something like python. For instance, I've actually implemented programs in Python that end up being so hilariously and frustratingly slow that I eventually gave up on working on them. Moreover, if I do have to concern myself with performance in rust, I feel like working in a language that uses RAII and doesn't wrap everything in pointers for GC by default provides a significantly clearer mental model for me of what my program is actually doing with its memory, and how my data is actually laid out, and I also typically have a clearer mental model of what CPU operations my program is actually doing as well. And in fact just having this clear mental model of what my program is actually doing helps me Implement more efficient algorithms and make cleaner and less wasteful programs in general, which I quite like. So yes, in essence I would turn the question back on the questioner and ask why they think they need a garbage collector and a language runtime and all of this extra stuff. Yes it does make the language marginally easier and quicker to write things in, but if I am sitting down to write a large scale program or long running project then being slowed down slightly in return for increased productivity.
- keybored 3y agoHonestly I feel like the Zeitgeist is that anything that smells of “optimization” is supposed to be preemptively justified. Like do you need a borrow checker or a static language or an AOT language implementation or...? Like anything that looks like they might by-default give you better performance (perish the thought) is supposed to be justified by some line about, oh well it turns out in our case that we need this thing actually, please forgive us for not using a dynamic language.
- logicprog 3y agoThat's a really good elaboration of what I'm getting at! Now that you mention it, it does seem like that's the case — as if people have taken the mantra about "premature optimization" way too far, to rule out not just micro optimizations, but also using good algorithms, and even starting with good foundations. As if by default we should be using the slowest and least efficient language and runtime possible, and any little concession to by-default performance (which in my opinion doesn't really count as optimization even) has to be justified by some particularity of your field or task. And honestly, I have to wonder if that's sort of the mentality that has led us to things like Electron. It makes sense to be worried about optimization for performance if it makes it makes your developer velocity clearly worse, but in my opinion, and according to what little research I've seen, the difference in development velocity between an ahead of time compiled statically typed language and a dynamic language quickly disappears beyond a certain program size, which makes sense to me, since it would be presumptively a constant factor.