3 ms·
> Rust comes with all the systems programming overhead, which in my opinion is not a good bargain if you are not, you know, programming systems. Alas, I’m too o
by lionkor 2y ago
> Rust comes with all the systems programming overhead, which in my opinion is not a good bargain if you are not, you know, programming systems. Alas, I’m too old to pick up my own garbage.
Granted, I'm a systems programmer, but I find the difference between Rust's memory model and a managed memory model (like C#'s) not very big. The only difference is that it's trivial to leak resources in C#, and it's very hard to leak resources in Rust.
Happy to get recommendations of a language that has both a GC or similar managed memory model, and also can manage all other resources the same way.
What Rust does right is what C++ tried to do; RAII. Memory is a resource, file- and socket-streams are resources, mutexes are resources, and they are all handled via the same principle that we all know and intuitively understand: Scopes. By extension, reference counting enables doing an AND of all the scopes.
I have never found that to be more mental overhead than, say, python, C#, or Golang, where forgetting to close a file, or forgetting to call Dispose(), or doing it twice by accident, or using mutexes, is a common source of nasty bugs. Extend this to the concurrency model Rust has, where both threads and async can be used, and all the resource management and borrowing just cleanly extends to that to avoid concurrency bugs, and you have unparalleled resource management.
- virexene 2y agoI'll have to disagree here. Leaking resources in Rust is pretty trivial: create an Rc cycle with internal mutability. By contrast, in languages with a GC, cycles will be properly collected. And there is nothing preventing GC languages from tying their non-memory resources to the lifetime of a value like Rust. See Python files, which are closed when the file handle is collected (ie. when all variables holding it go out of scope), and if that's not explicit enough, there's the "with" keyword to explicitly introduce a scope at the end of which the file is closed.
- pessimizer 2y ago> Leaking resources in Rust is pretty trivial: create an Rc cycle with internal mutability. It's trivial to do on purpose, but difficult to do accidentally.
- lionkor 2y agoIn Rust, the default behavior when using resources like any other type is correct. You have to introduce a specific type to leak them. In Python, you need to handle resources differently and introduce a language feature to not leak them. That's the difference you're pointing out.
- nemetroid 2y ago> See Python files, which are closed when the file handle is collected (ie. when all variables holding it go out of scope) That's a CPython implementation detail. https://docs.python.org/3/reference/datamodel.html https://docs.python.org/3/reference/datamodel.html > Do not depend on immediate finalization of objects when they become unreachable (so you should always close files explicitly).
- neonsunset 2y agoIn Go, you have to explicitly do a defer. In C#, you just write `using var file = File.Open(...);`. Some methods handle disposal for you - you never interact with it if all you need is foreach (var line in File.ReadLines("example.txt")) { ... } Here, file handle will be opened once you start enumeration and will be closed through enumerator disposal which is one of the calls foreach is desugared into (to be accurate, this specific implementation will also close the handle when reading the last line, but I'd expect user-authored type to do handle closure through dispose implementation only) I agree that Rust implicitly inserting drop() by proving the exact place the value gets dropped at is superior, but C# experience is not exactly terrible either.
- pjmlp 2y agoAdditionally, there are Roslyn analysers that will complain when we forget about using.
- CharlieDigital 2y agoTo be clear, `Dispose()` (aka `using`) is not the same as GC. It just cleans up unmanaged resources (connections, file handles, etc.) and marks the managed entity available for GC.
- pjmlp 2y agoDepends, C# and .NET in general have support for manual memory management, it is a matter how it was allocated in first place. People keep forgetting CLR was designed to accommodate C++ as well, and during the years some of those capabilities have been exposed to other languages in more easier ways than reaching out to C++/CLI.
- lionkor 2y agoOf course, I understand you don't leak resources if you pay attention and use linters. However, default out-of-scope behavior doesn't exist. In Go, you can defer, and you can also forget to defer. The default behavior is that resource cleanup is a program logic problem that is entirely on the programmer. The same applies to C#: You program your resource freeing with Dispose (okay, fair so far), and then if the caller forgets to Dispose, you leak. Again, the default behavior is that resource cleanup is a part of the explicitly implemented logic, always. Compare that to Rust, where you can explicitly drop(), but once a value goes out of scope, its resources are freed. This is about default and consistent behavior. C# and Go handle memory as a special resource you only sometimes, only in some ways, need to worry about (new, make) but most other resources (files, sockets, threads (if they exist)) become an afterthought and have special logic the programmer needs to worry about *by default*.