5 ms·
The problem with garbage collection is that it doesn't work for other kinds of resources than memory, so basically every garbage collected runtime ends up with
by Nullabillity 3y ago
The problem with garbage collection is that it doesn't work for other kinds of resources than memory, so basically every garbage collected runtime ends up with an awkward and kinda-broken version of RAII anyway (Closeable, defer, using/try-with-resources, context managers, etc).
Static lifetimes are also a large part of the rest of Rust's safety features (like statically enforced thread-safety).
A usable Rust-without-lifetimes would end up looking a lot more like Haskell than Go.
- pphysch 3y ago> The problem with garbage collection is that it doesn't work for other kinds of resources than memory Why is that a "problem with GC"? Abstracting away >90% of resource management (i.e. local memory) is a significant benefit. It's like saying the "problem with timesharing OS" is that it doesn't address 100% of concurrency/parallelism needs.
- insanitybit 3y agoI think a charitable reading would be that by "problem" they meant "limitation".
- pbourke 3y agoI quite like context managers and try-with-resources style constructs. They make lifetimes explicit in the code in a fairly intuitive way. You can get yourself turned around if you deeply nest them, etc but there are usually ways to avoid those traps.
- ok123456 3y agoDon't static lifetimes just mean that leaking memory is considered 'safe' in rust?
- Nullabillity 3y agoStatic lifetimes as in "known and verified at compile-time", not "the 'static lifetime".
- eternityforest 3y agoPython handles all kinds of stuff with garbage collection. The problem is that things like closing a socket are not just generic resources, a lot of the time nonmemory stuff has to be closed at a certain point in the program, for correctness, and you can't just let GC get to it whenever.
- mplanchard 3y agoI don’t think this is true. Context managers call special magic “dunder” methods on the instance (I don’t remember the specific ones), and I’m pretty sure those don’t get called during regular garbage collection of those instances. It’s been a few years since I was regularly writing python, so I might be wrong, but I don’t believe that context manager friendly instances are the same as Rust’s Drop trait, and I don’t think their cleanup code gets called during GC.
- Nullabillity 3y agoPython is a fun case of "all of the above" (or rather, a layering of styles once it turns out a previous one isn't workable). Originally, they used pure reference counting GC, with finalizers used to clean up when freed. This was "fine", since RC is deterministic. Everything is freed when the last reference is deleted, nice and simple. But reference counting can't detect reference cycles, so eventually they added a secondary tracing garbage collector to handle them. But tracing GC isn't deterministic anymore, so this also meant a shift to manual resource management. That turned out to be embarrassing enough that context managers were eventually introduced to paper over it. But all four mechanisms still exist and "work" in the language today.
- mplanchard 3y agoWrote Python professionally for years and didn’t know all of this. Thanks!
- im3w1l 3y agoAre you saying that a finalizer is guaranteed to run when the last reference is deleted? So you could actually rely on them to handle the resources, as long as you are careful not to use reference cycles?
- nextaccountic 3y ago> basically every garbage collected runtime ends up with an awkward and kinda-broken version of RAII anyway (Closeable, defer, using/try-with-resources, context managers, etc). RAII works only for the simplest case: when your cleanup takes no parameters, when the cleanup doesn't perform async operations, etc. Rust has RAII but it's unusable in async because the drop method isn't itself async (and thus may block the whole thread if it does I/O)
- paholg 3y agoThere are workarounds. You could, for example, have a drop implementation spawn a task to do the I/O and exit. Also, if your cleanup takes parameters, you can just store them in the struct.
- Gwypaas 3y agoIn my experience async drop is a nice to have, not a must. Futures::block_on is good enough for the happy path in low stakes scenarios. When dealing with async operations they tend to end up at a network boundary and thus the service enters distributed system land. Now the async drop also has to handle the server crashing before the drop happens and at any time when it happens. Keeping that in mind trying to actually drop something becomes quite meaningless since you need to handle all other cases either way.
- klabb3 3y agoI agree but does RAII necessarily imply parameter-free destruction? Personally I love Rust’s `fn foo(self, …)`, which is just like a regular method but consumes the value. Deallocate by default is fine, but sometimes you need to run specific destructors (linear type style). I’ve long wished for an opt-out from implicit drop semantics for resource/handle types.
- Nullabillity 3y agoYou can (kind of) emulate linear types by making `drop()` unlinkable[0]. Of course, I wouldn't recommend doing this since the error messages are awful and give no explanation at all of where the actual problem is... [0]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=d6004cc32fa199c118378c1e984cb580 https://play.rust-lang.org/?version=stable&mode=debug&editio...
- jayd16 3y agoYou make an interesting point. Has any language introduced a generic-resource-collector? You're not supposed to use deconstructors to clean up resources because you're left to the whims of the GC which is only concerned about memory. Has anyone build a collector that tracks multiple types of resources an object might consume? It seems possible.
- jerf 3y agoErlang is probably the closest. The word you want to search for is "port". If it doesn't seem like it at first, keep reading. It's a very idiosyncratic take on the topic of you view it from this perspective because it isn't exactly their focus. But it does have a mechanism for collecting files, sockets, open pipes to other programs, and a number of other things. Not fully generic, though.
- PaulHoule 3y agoPeople miss that there is a quantitative aspect to these things as well as a qualitative aspect. That is, many programs allocate millions of pieces of memory a second and for a wide range of different purposes whereas there might be a limited number of other resources of an even more limited set of types. Any change in the code probably has some affect on memory allocation, but many changes won't have any effect on allocation of higher-level resources. Thus the complexity of handling memory is greater than that of other resources and the consequences of getting it not 100% right are frequently worse.