3 ms·
Apart from syntax sugar over which I agree should be improved, the argument sells to boil down to: my language doesn't enforce a borrow checker so it is UB safe
by Sytten 2y ago
Apart from syntax sugar over which I agree should be improved, the argument sells to boil down to: my language doesn't enforce a borrow checker so it is UB safe. Which in my book is just not true.
The allocator example the user gives is not really good since if he had another try in between the alloc/free I assume the memory would not be freed, Drop semantic is better in that regard. You can also set a global alloc that check for missing free in rust though probably not as nice as a localized one.
- hansvm 2y ago> try between the alloc/free The idiomatic way to handle that is with some combination of `defer` and `errdefer`. Then, in code, there are no lines between alloc/free, and if a try would exit before the free then you would instead first free anyway. > drop semantic is better in that regard The drop trait has its warts too. Zig's version sets up a point in time where the given cleanup code _will_ run (ignoring power outages and the like), and Rust's sets up a point in time where the given cleanup code is _allowed_ to run. It solves UAF, but it makes performance harder to reason about and makes leaks easier to write (a common theme in my complaints about Rust -- it's mostly a nice language, but many of the design choices slightly encourage leaky code, so most projects of any size and complexity have leaks). Having drops be that easy to write also encourages programmers to think in terms of small units of data rather than collections and common lifetimes, typically resulting in increased execution times.
- Sytten 2y agoYou literally don't leak memory in safe rust, that is kinda of the whole point. If you use smart pointers sure you can leak but that is not only rust, any ref counted abstraction has that. Drop IMO is preferred over defer because you can't forget to call a free. If you encapsulate your unsafe (which you should), you can guarantee it will be freed. I much prefer that. If you want to free early just call drop manually, after that if the memory is not freed then that on you to set an allocator basedon your needs.
- estebank 2y agoI like Drop. Memory leaks in Rust are incredibly uncommon. But they are considered memory safe. Box::leak is declared safe, as per the leakpocalipse right before 1.0. A memory leak that is still pointed at by a dangling pointer is not going to cause UB, even though it is still a bug.
- hansvm 2y ago> You literally don't leak memory in safe rust, that is kinda of the whole point. That's a common misconception. Safe Rust prevents use-after-free, double-free, accessing uninitialized memory, (an extremely constrained form of) data races, and a number of other things. It doesn't give a rip about leaks beyond a best effort. Leaks do not violate memory safety. Part of the reason it doesn't care is because it's hard to infer your intent. A common class of bug is accidentally boxing a reference to something you'd like to drop (this and similar flaws afflicted Actix till at least the 3.0 release). Rust confirms you don't have UAF and that you don't drop the data before you're done with it, but by accidentally writing it so that it lives nearly forever that drop is never executed. Rust, similarly, makes no guarantees about drop's behavior at any point in time (other than that it won't be executed to soon and should usually attempt to be executed eventually), but definitely not near program shutdown or similar. It's especially dangerous because a huge fraction of programs run correctly regardless most of the time.
- nurettin 2y ago> You literally don't leak memory in safe rust, that is kinda of the whole point. Memory leak is not the same as dangling reference. A loop pushing too many values into a vector can be considered as a memory leak.
- estebank 2y ago> The drop trait has its warts too. Zig's version sets up a point in time where the given cleanup code _will_ run (ignoring power outages and the like), and Rust's sets up a point in time where the given cleanup code is _allowed_ to run. You're making it sound like Drop is regularly not called, which could lead someone to think that you're talking about them not running on panics, which they do: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=e1f04f91722cc4220995f4bda922ed70 https://play.rust-lang.org/?version=stable&mode=debug&editio... The reason they are allowed to run is because panics can be configured to be abort, so people are discouraged from using Drop to maintain safety constraints. But any language will have issue executing code before exiting if you go out of your way to set things up so normal unwinding doesn't occur. > It solves UAF, but it makes performance harder to reason about and makes leaks easier to write (a common theme in my complaints about Rust -- it's mostly a nice language, but many of the design choices slightly encourage leaky code, so most projects of any size and complexity have leaks). I don't see how Drop causes leaks. > Having drops be that easy to write also encourages programmers to think in terms of small units of data rather than collections and common lifetimes, typically resulting in increased execution times. Beyond my skepticism about the mechanism being a significant source of performance degradation, writing collections that take responsibility over dropping their contents in one go isn't particularly difficult or restricted by the language.
- hansvm 2y ago> You're making it sound like Drop is regularly not called Sorry if it came across that way. My claim is weaker, that it's sometimes not called even in cases where it could be with a smart enough programmer/language. > But any language will have issue executing code before exiting if you go out of your way to... Is there an easy way to make Drop work nicely with signal handler induced shutdowns other than having a "correctly" configured panic handler and panicking in the signal handler (even that causing other UB depending on what code Drop runs)? The edge cases for the feature look thorny from my perspective, but (some) other languages handle that by forcing you to be explicit about which code runs when. > I don't see how Drop causes leaks "Relying" on Drop is the most common source of Drop-related leaks. All it takes is one extra reference to cause leaky code (see Actix as a case study in such problems). > Beyond my skepticism about the mechanism being a significant source of performance degradation That's... pretty easy to test? Pick any problem that potentially has a lot of allocations, like an async sudoku solver, and check how it performs with a collection (arena, pool, ...) vs using Drop on each item. I promise the difference is substantial. > writing collections that take responsibility over dropping their contents in one go isn't particularly difficult or restricted by the language No, not at all. I totally agree. The concept of "intentional friction" is useful here. An expert can make excellent Rust code. My last job had one person like that (not that it matters, but that was out of many people who wrote Rust there), and you have shining examples like BurntSushi. My complaint is that the language's happy path doesn't guard against those performance mishaps, and since most Rust code I see in the wild has fallen prey to those pitfalls I think it's a reasonable complaint.
- pod_krad 2y ago>The idiomatic way to handle that is with some combination of `defer` and `errdefer`. Then, in code, there are no lines between alloc/free, and if a try would exit before the free then you would instead first free anyway. Do I understand correctly, that talking about idiomatic way is the same as talking about programming style, but not about language semantic?
- hansvm 2y agoCorrect. Much like in Python or C, you can explicitly handle every error/break/early-return condition and manually free the resource. Each language offers a tool to make that easier (and more likely to be correct, especially as the code changes) in most cases though. In Python it's try/finally, in C it's `goto ERR`, and in Zig it's defer/errdefer.
- pod_krad 2y agoSo, you can't rely that someone will follow that style in Zig. That is my point.