← Back to context

Comment by nihsett

12 hours ago

Exactly. 95% of programmers are application programmers - they ship software used by regular users. I think it's insane to use a non-GC language for most of those cases. Manual memory management is mentally taxing and it's easy to make catastrophic mistakes. The marginal benefit from it is just not worth it unless you're making games or a trading system.

5% who write tools or other "infra" layer for the other 95% to work on top of maybe need that level of control over memory. It doesn't make any sense to me to sign up for that complexity unless you really really need it.

Maybe I'm misunderstanding something but non-GC language doesn't mean you have to do memory management manually? I mean, for example, in Rust (or modern C++), it's basically automatic. There is no mental tax or catastrophic mistakes as far as I know.

  • Ok.

    https://rust-unofficial.github.io/too-many-lists/

    I'm not saying Rust is worse than Go. It obviously isn't. But this argument that Rust's memory management isn't more cognitively demanding than Go's memory management --- that isn't true.

    • Certainly you pay a price for lifetimes but you buy compile time race condition detection via the borrow checker's aliasing-xor-mutability enforcement. So all that is happening is the complexity of concurrency is being made explicit and therefore easier to reason about. Many applications can be architected in a way that wouldn't ever trigger a race, so for people working on that it isn't something they would need to reason about and they can call it unneeded complexity. This is the simpler vs. simplistic distinction also made in the article. If you can be simplistic, garbage collection is less cognitively demanding, but if you are designing race free algorithms with shared memory then rust will be. I do believe more developers and applications live in the former.

      The better example actually comes from the article: returning a struct and an iterator over that struct isn't possible in rust. Heck, initializing a struct to return an iterator might lead to issues. Most people will encounter this before needing a linked list and the lesson it teaches will help out with the linked list.

      2 replies →

    • > But this argument that Rust's memory management isn't more cognitively demanding than Go's memory management --- that isn't true.

      It's not far from true. The fights you get into with the borrow checker can be legendary, but lifetimes serve more as gentle reminders. If you get stuck, you can always just use Rc, which is pretty close to opt-in GC. But it's rare to have to resort to Rc, because ownership is just not that much of a problem. In fact, I very rarely use Box either. All heap memory allocation is done by containers, not manually by me. I guess the main friction point for lifetimes is Rust's closures and async, but if you avoid them life is pretty simple.

      In return for wearing this almost not a problem, you almost don't have to think about releasing a whole pile of other things - like closing files, sockets, and locks. They are guaranteed to be released by the same mechanism.

      On balance, I would not be surprised if the cognitive balance tips Rust's way once you allow for the fact that Rust's memory management also gives you robust resource management for free.

    • How is Aria's linked list document relevant on this topic? Go is the kind of language where they'd call their growable array type "List" because why not. C# did that in fact, when it gained generics they named their generic growable array List<T>

      So the linked list is a thing Go doesn't have at all, in Go the equivalent document probably just reminds you of Go's rule "Don't be clever". Thanks Go, I'll keep it in mind.

      Generally the argument is that non-GC languages require you to worry about memory management because of Use-after-free, but of course safe Rust just won't compile if you wrote a typical use-after-free so that's not really extra cognitive demand.

  • You seem to imply that it doesn’t have any cost. It does. You have to make decisions and, in the case of C++: sometimes you have to deal with a lot of really ugly code to make it “automatic”. And if you really have to count bytes and carefully manage stack sizes because you are writing code for a constrained device, you have to pay even more attention than you would in C.

    GC’ed languages have memory related challenges too. But it simply isn’t true that these are on the same order of difficulty as the difficulties that do arise in C++.

Or it could be insane to pay the cloud memory costs when you have tools that can write rust for you.

  • What "cloud memory costs"? Most Rust code is an informally-specified version of the old Python reference-counting GC. That's how you're supposed to write it, with clone() everywhere, and then dropping down to optimize. You can do the same thing with Go in the other direction by writing an allocator.

    People believe a lot of weird things about these languages.

This post is specifically about backend development, where you're not shipping software to regular users.

  • This is just a matter of perspective. Backend IS being "shipped" to user via the API be it go or rust and inevitably the details and behavior do leak out to end user.