> I believe everyone agrees that a "better C" has to have manual memory management.
This seems completely wrong. Manual memory management is perhaps C's most famous issue. I'm sure _someone_ thinks manual memory management is a feature rather than a bug, but I don't think there's any broad consensus about this at all.
Moreover, Go gives you a lot of levers to control your allocations, and with some care (probably less care than writing correct C code) you can avoid allocating at all (this is how Go's own runtime works).
> Manual memory management is perhaps C's most famous issue
C's most famous issue is that it doesn't have a dynamic memory management concept at all. You can implement manual memory management on top of C, like you can in any language, but it is not a core feature. If C had manual memory management then it could be reasoned about, which would avoid many of the pitfalls associated with memory management being bolted on top.
Whether that is a feature or a bug probably depends on what kind of software you are building. If you are targeting a PC, a dynamic memory management concept in the language can be useful. If you are targeting a small microcontroller where you don't want dynamic allocation then things can get a bit weird having language features that need to be disabled or having to rely on outside processes (code review, linters, etc.) to control use.
But the general consensus these days does seem to be that a language should include a dynamic memory management concept, even if it is sometimes disabled. So a "better C" likely would gain memory management, but you make a fair point that it doesn't have to be manual in nature.
> C's most famous issue is that it doesn't have a dynamic memory management concept at all. You can implement manual memory management on top of C, like you can in any language, but it is not a core feature. If C had manual memory management then it could be reasoned about, which would avoid many of the pitfalls associated with memory management being bolted on top
It seems like you’re conflating dynamic and manual memory management? Or maybe you are using these terms in a way I’m unfamiliar with. C definitely has manual memory management via malloc and free. It can be reasoned about, but doing so correctly is very difficult (this is what Rust’s ownership system formalizes, after all). I don’t think this is controversial?
> If you are targeting a small microcontroller where you don't want dynamic allocation then things can get a bit weird having language features that need to be disabled or having to rely on outside processes (code review, linters, etc.) to control use.
C has dynamic memory (again, malloc and free) and thus it is in the same boat as other languages that have to take care to avoid using dynamic memory when writing embedded code (a decade and a half ago I was an embedded engineer using C and C++).
Perhaps I should have said heap memory to be more clear, but the intent was to recognize that C does have memory management (the stack), but it manages it automatically. However, I don't think the intent was actually lost as you specifically called out malloc, which was directionally correct. So I guess there was no need to be more clear as the message was delivered just fine.
> C definitely has manual memory management via malloc
No. malloc isn't part of the C language, it is a library function and one that isn't guaranteed to be available at that.
> It can be reasoned about, but doing so correctly is very difficult
To the best of our knowledge it is impossible. That is why Rust's claim to fame is adding a model necessary to make reasoning about memory possible.
> C has dynamic memory (again, malloc and free)
Again, malloc and free are not language features. They are bolted on top. You can bolt malloc and free onto every language under the sun. You can even bolt malloc and free onto Rust, but you will then break the ability to reason about its memory if you use it.
malloc and free are part of the C standard library. I don’t see the point in picking nits between language features you don’t have to use and standard library functions that you don’t have to use.
When you called attention to Rust you clearly understood the point of picking nits. Why pretend you have no idea what we are talking about now?
malloc/free, not being a language feature, cannot be reasoned about. Since the larger discussion is about Go, consider using malloc/free in Go. Of course you can do it. There is nothing stopping you. Since it is not part of a language it can be bolted on to any language, not just C. But if you do, it should be obvious you can no longer reason about the program in terms of how memory is used. If there was a way to reason about it, C would already have all the same memory guarantees that Rust does.
> malloc/free, not being a language feature, cannot be reasoned about.
They’re defined in the standard all the same. Of course they can be reasoned with. The defined parts at least. You may argue that the undefined parts cannot, but those are explicitly outside the scope of the C standard, no need to discuss them any further.
> It can be reasoned about, but doing so correctly is very difficult […]. I don’t think this is controversial?
It’s actually much easier than 95% of programmers think. The trick is to stop using fine grained allocations all the time, which are very difficult without tricks like RAII or a borrow checker (not to mention the high runtime overhead), and start using arenas instead. https://www.rfleury.com/p/untangling-lifetimes-the-arena-all...
> I'm sure _someone_ thinks manual memory management is a feature rather than a bug,
I reckon mandatory manual memory management is not ideal. But the ability to manage some memory manually, including in cases that require something more flexible than a stack, is definitely a feature.
I believe every willing user of Zig, Odin, and Rust would agree with me on this one.
> […] with some care […] you can avoid allocating at all […]
As long as it’s crystal clear from the source code, or I have a tool that tells me which line of mine is responsible for the allocation.
Then it needs to be made standard. Without that, or an equivalent solution, garbage collected languages will remain unusable in constrained environments.
I'm not sure I agree (or maybe I misunderstand--I assume you're saying "the tool needs to be standard"?), but people use non-standard tools in C all the time. Every build tool or package management solution in C is non-standard. Every memory analyzer or static analysis solution is non-standard.
I think the real impediment isn't related to garbage collection, but it's just ecosystem inertia and industry knowledge inertia--the same forces that inhibit Rust adoption or C++ adoption or Ada adoption. Does that seem reasonable, or am I misunderstanding? What do you think?
I mean it needs to be made standard because of how bloody useful that is. More people need to be made aware (industry knowledge inertia), and it needs to be usable pretty much everywhere (ecosystem inertia).
C and C++ start out so unsafe, I can hardly use them on substantial projects without sanitisers now. Sanitisers need to be made standard so I can use them everywhere.
Garbage collected languages start out with unpredictable memory usage, making them unusable on constrained environments without the relevant memory analysers (static or dynamic). Such tools need to be made standard so garbage collection may be an option on more platforms.
This seems completely wrong. Manual memory management is perhaps C's most famous issue. I'm sure _someone_ thinks manual memory management is a feature rather than a bug, but I don't think there's any broad consensus about this at all.
Moreover, Go gives you a lot of levers to control your allocations, and with some care (probably less care than writing correct C code) you can avoid allocating at all (this is how Go's own runtime works).