4 ms·
There's just not a language feature to prevent you from letting an object go out of scope without "using" it. There is `Drop`, which automatically runs when an
by Rusky 4y ago
There's just not a language feature to prevent you from letting an object go out of scope without "using" it.
There is `Drop`, which automatically runs when an object goes out of scope, but you can skip that by leaking the object, e.g. with an Rc cycle.
There is also `#[must_use]`, which warns when you don't do anything with an object, but you can explicitly silence that with `let _ = the_object` or `let _bla = the_object`, and it doesn't complain if you exit that scope early (either via normal control flow or panic).
The reason Rust has `Drop` and `#[must_use]` but not linear types (short of "nobody's bothered yet") is that they aren't really all that pleasant to use and they impose a lot of constraints on the APIs you build with them. You would have to prevent leaks of linear objects (which means, among other things, no reference counting or moving between threads!). You would have to track panics in the type system and/or forbid calling most functions while a linear object is live. More detail here: https://gankra.github.io/blah/linear-rust/ https://gankra.github.io/blah/linear-rust/
The current design means the default way to use a `File` won't handle errors on close, but you can opt into that by making an explicit call yourself. In exchange, you can do a lot of things with `File` objects that you couldn't with a linear `File`. (My suspicion is that Vale either doesn't use linear types for files, doesn't actually enforce linearity at compile time, or makes files painful to use with generic code.)
- verdagon 4y agoI've been using higher RAII with Vale for quite a while, and it doesn't have the problems Rust seems to have. It's actually not difficult to design APIs to properly use handles and other RAII'd objects. Either don't drop generic types (for example, the HashMap doesn't drop any user types), or require a drop generic bound or concept function [0]. If one wants to make it even easier, just take in a "consume" lambda which will take arguments. Then, the caller can specify what to do with these objects. That's how Vale's drop_into function for arrays work, for example. In my opinion, Rust made the same mistake with `drop` that Java made with `toString` and `hashCode`. We shouldn't needlessly couple functionality with objects, it just causes problems, as is seen with Rust's lack of linear typing. But that's just my opinion ;) [0] https://verdagon.dev/blog/concept-functions https://verdagon.dev/blog/concept-functions
- tialaramex 4y agoThe trouble with Vale's "concept function" and the C++ Concepts it is mimicking is that they're duck typed. We know syntactically that we can do this, but there's no reason to believe it's semantically justified. This is why you'll notice Rust's traits don't have names like "Iterable" or "MaybeComparable" but "Iterator" and "PartialOrd". They have semantics. Rust's Iterator is not merely any thing which happens to have a next() method but specifically a iterator in which that next() method gets to the next item. Over in Concepts land they have two "fixes" for this, but they're both pretty unsatisfactory. One fix is, you document what the concept means, and then you just tell the programmer it's their fault when the syntax matches (so it compiles) but the semantics don't (so it's broken). The other is, just tell people not to use Concepts for simple things, if it's complicated enough then likely the syntax will only match when semantically aligned. Unfortunately of course lots of powerful er, concepts, have exactly one match point. This is funniest when in juxtaposition e.g. Stroustrup first showing off concepts with a simple example like your Fireable concept back in 2018 or so, mixed with Stroustrup in 2020 explaining that it's crucial never to do anything like that because it's too fragile...
- verdagon 4y agoThat's not quite correct. Concept functions can easily be checked ahead of time, theyre basically generics under the hood. C++ uses duck typing, but Vale doesn't have to. If it helps, think of it this way: a concept function is a 1-method trait on an implicit parameter.
- tialaramex 4y ago> If it helps, think of it this way: a concept function is a 1-method trait on an implicit parameter. No, that just underscores the problem, it's just duck typing. This "1-method trait on an implicit parameter" doesn't deliver semantics. Let's look at an actual Rust trait, Eq. https://doc.rust-lang.org/std/cmp/trait.Eq.html https://doc.rust-lang.org/std/cmp/trait.Eq.html and notice that the implementation of this trait is empty. For a duck typing system there is nothing to check, syntactically Eq doesn't do anything. But of course semantically Eq is rich with meaning. You can't go around using a HashMap with keys that don't exhibit Equivalence, what's that going to do? Nothing good.