4 ms·
> which is tied to lexical scope This isn't really true. It is kinda true in C++ but fairly well fixed with moves. In Rust it isn't true at all because moves a
by kevincox 4y ago
> which is tied to lexical scope
This isn't really true. It is kinda true in C++ but fairly well fixed with moves. In Rust it isn't true at all because moves are the default so any time you return a value or put it in a data structure the lifetime is no longer lexically bound.
> It's hardly "wrong by default" and more "understandably different."
I think it is both. What I mean by "wrong by default" is that if you write
f = open(name)
The code is now wrong. This is the default behaviour. To make the code corred you need to add a second bit of code (a close call). Defer is a powerful mechanism to do that, but it is a tool to solve the core wrongness.
- masklinn 4y agoNote that they said the destruction is tied to lexical scope, in general, not necessarily the lexical scope of creation. Their point is mostly that once you "drop" an object in a GC'd language, it will be collected at some later time independent of lexical scope. Which I don't think is much of an issue, technically the language could "drop" (close) such objects lexically and leave memory reclamation for later. Not a huge issue. The bigger issue is that GC-based objects have a strong tendency to share, a lot. That makes RAII way more challenging, when using the objects directly for starters, but even more so when composing RAII objects and non-RAII objects.
- marcosdumay 4y agoOn both C++ and Rust the destruction is tied to the value's lifetime. On the two languages that everybody remember when they talk about RAII, the destruction is not tied to lexical scope. (Although, on C++ that requires extra code for your class to behave correctly. The resource managing class is wrong by default, but the code that uses it is not.)
- tialaramex 4y agoIn Rust what you wrote is just how it works because it's how move was defined in the language, but I think in C++ at most you could say that this is how people conceptually try to arrange for things to happen, and at that point we're back to "Wrong by Default". All the C++ compiler actually gives you is destruction at end of lexical scope, and then it's your job as programmer to do what people actually wanted instead. Historically what you do in C++ is copy things a lot, or work with pointers. Modern C++ offers a move, but for backwards compatibility reasons it had to preserve that behaviour where the destruction happens precisely when you leave scope, so, move "hollows out" objects, leaving something which can be destroyed later. Thus it's your job, when implementing a C++ type, to ensure that the "real" work happens whenever a programmer would expect, leaving just some shell to be properly "destroyed" later when scope ends. Whereas for Rust you just implement Drop correctly and the compiler arranges for it to happen promptly.
- MauranKilom 4y ago> All the C++ compiler actually gives you is destruction at end of lexical scope, and then it's your job as programmer to do what people actually wanted instead. `new` and `delete` are built into the language (and smart pointers into the standard library). The statement that object lifetime is tied to lexical scope is plainly untrue. > Thus it's your job, when implementing a C++ type, to ensure that the "real" work happens whenever a programmer would expect The auto-generated (`= default`) copy and move constructors do the right thing by default if you compose your type from other (correct) types. Yes, in the rare case that you write a type that has to implement RAII, the compiler can do the wrong thing by default ("copy just copies the pointer"), but then you write a wrapper class once and you're done. If that's even necessary at all, since unique_ptr can have custom deleters. (You wouldn't violate Single Responsibility by messing with RAII in a class that also does other things, right?)