5 ms·
> Rust is the first language to bring non-GC automatic memory management to the mainstream. It won't be the last and it might well be the worst. Other languages
by est31 2y ago
> Rust is the first language to bring non-GC automatic memory management to the mainstream. It won't be the last and it might well be the worst. Other languages in this space include Swift
Rust's memory management is not automatic, you have to explicitly manage memory. It's just made extremely easy for you by the language thanks to stuff like RAII, and there is checks that prevent memory safety violations like double free. But those checks won't prevent leaks, although the many lints do make it harder to forget about a value.
Also, Swift's refcounting can be seen as a form of gc.
- kaba0 2y agoYeah, the correct statement would be ‘Rust is the first mainstream language without GC, that guarantees memory safety’ (with obviously the caveat of unsafe blocks, but than you can also sun.misc.unsafe yourself into segfault in java).
- lolinder 2y ago> Rust's memory management is not automatic, you have to explicitly manage memory. It's just made extremely easy for you by the language thanks to stuff like RAII, and there is checks that prevent memory safety violations like double free. But those checks won't prevent leaks, although the many lints do make it harder to forget about a value. By this logic no language on earth has automatic memory management. I've spent time troubleshooting a memory leak in JavaScript in the past month, caused by someone keeping a pointer around longer than necessary. Rust's memory management is automatic in that you can write entire Rust programs without once calling `free` manually. I'm not sure what definition of automatic you're working off of, but if it excludes JavaScript it doesn't seem especially useful.
- bryancoxwell 2y agoPointers in JavaScript? I’m far from a JS expert, but didn’t think the language had pointers. Could you explain what you mean here?
- lolinder 2y agoI'm not aware of any mainstream language that doesn't have pointers, the question is whether they expose pointers as a first-class language construct (i.e. you can choose to not dereference them or to do pointer arithmetic) or use them as an implementation detail. In JavaScript's case it's an implementation detail, but one that is extremely relevant when maintaining something in production.
- bryancoxwell 2y agoMakes sense, thanks!
- bobajeff 2y agoCorrection about JavaScript: All non-primitive data types are pass by reference. So not just implementation detail as no valid js interpreter will pass those by value.
- lolinder 2y agoIt's not up to the implementation to decide whether to pass by reference or not, but it is up to the implementation whether to use pointers under the hood to model passing by reference. Since there's no pointer arithmetic, other models could theoretically be used to accomplish the same semantics [0], it just happens to be that pointers are by far the most logical choice. [0] As a silly example: a JavaScript implementation could technically store object references as a URL of an API that allows interacting with the object, as long as this is transparent to the user and the program behaves the same as a pointer implementation (minus non-functional characteristics like performance).
- mind-blight 2y agoMost variables on JavaScript are (essentially) pointers. A common mistake people make in the language is keeping references to objects in a global map, which prevents them from being garbage collected (often a bad caching implementation). You can use things like WeakMap or WeakRef as one solution, but there are usually better options
- Measter 2y agoI've found it's kinda helpful to think of Rust/modern C++ style management as semi-automatic memory management. You control when things are allocated and freed, but you don't bother with the minutia of it unless you're writing a low-level container type. This is contrast to something like C/Zig, where things are fully manual, or something like Python or Javascript where things are fully handled for you.
- pessimizer 2y ago> you can write entire Rust programs without once calling `free` manually. If you mean "drop," it's just syntactic sugar for calling a trait that manually deallocates the memory and that you're free to reimplement. It feels like people are equating "manual memory management" with "onerous memory management." People are usually going to want to do the boring thing with memory, and everything in the standard library by default does the boring thing with memory. If you write boring structs and enums, you'll derive boring memory management. But it's not part of the language, it's part of the library.
- lolinder 2y ago> If you mean "drop," it's just syntactic sugar for calling a trait that manually deallocates the memory and that you're free to reimplement. I meant `free` because I'm contrasting with C. > It feels like people are equating "manual memory management" with "onerous memory management." Manual memory management is onerous, but I'm very specifically talking about manual. If I can write a whole program without thinking about memory, the language does not require manual memory management. It may support it, but it doesn't require it the way that C or Zig do. You do not "have to explicitly manage memory" as OP claimed.
- tialaramex 2y agoYou can't call Drop::drop for type T at all. Try it if you don't believe me. It would be unacceptable to allow this because Drop::drop says it only takes a mutable reference &mut T (and indeed it does) but now the thing is destroyed, so, that wasn't just a mutable reference at all! You can call core::mem::drop<T> but well, look at it, here's the code: pub fn drop<T>(_x: T) {} Like, duh, we give it a T and then it doesn't give anything, the T is gone. That's not magic library code by the way, if we make our own: pub fn vanish<T>(_x: T) {} Now we can call our vanish function and the same happens. So yeah, automatic memory management.
- consteval 2y agoTo be fair I don't think this is enough to say automatic memory management, otherwise C++ would be automatic memory management too (and maybe it is, just poorly implemented?)
- est31 2y ago> Rust's memory management is automatic in that you can write entire Rust programs without once calling `free` manually. Personally I'd put the bar around not requiring people to distinguish different pointer types (owned vs shared). Languages like Java, JS, Python, Swift, Go, etc all have this "everything is a smart pointer" paradigm, (or at least the strong and widely used default). I'd say Rust is manually managed because you need to think about which pointer type to use and using gc'd pointer types like Arc has a syntax overhead (like say when a pointer is cloned).
- iknowstuff 2y agoSwift has „weak” references for when you don’t want to bump the reference count. Does that make it manual?
- consteval 2y agoMost GC langs have these features too they're just not in your face. Technically C# has true value types like C++. Rust makes the distinction between stack and heap references, like C++. Other, more high-level languages don't - there's only one kind of reference, you can't take a reference to a stack object. Maybe you implement that by making all objects heap allocating (Java) or you just say they have to be copied every time (C# struct). That's really where the difference is. There's a lot of juicy, juicy performance there. The problem is taking references to stack variables is problematic. Tracking heap objects with a GC or a ref counter is really trivial in comparison IMO, at least when you try to combine the systems.
- neonsunset 2y agoThe assessment on C# does not match language spec at all. Not only instance methods on C# structs are implicitly byref, you can easily pass structs by reference via ref, out and in keywords. On top of that, ref structs can hold `byref` pointers aka 'ref' keyword which can point to arbitrary memory, or have references to other structs/variables/anything. There is also regular C syntax with &T and T* for unmanaged references/pointers. On top of that, .NET's compiler has gotten very good at struct optimizations and pretty much ensures they stay in registers all the time unless address-taken, including SIMD registers for Vector<T> and Vector128/256/512<T> even their "deconstructed" form when specified width is not supported so they get handled as e.g. 256x2. There was a big jump in codegen quality in .NET 8 which can now sometimes trade blows with GCC and Clang around struct optimizations. All these features are first-class and are heavily used by all kinds of performance-sensitive code. Also, structs can implement interfaces and can be generic arguments that satisfy interface constraints, which works exactly like generics with trait bounds in Rust - you get a generic instantiation aka monomorphized function body, making the abstraction zero-cost.