5 ms·
As far as I know, Vale is the only language that can statically ensure we handle that error with its Higher RAII [0], a form of linear typing. Basically, File'
by verdagon 4y ago
As far as I know, Vale is the only language that can statically ensure we handle that error with its Higher RAII [0], a form of linear typing.
Basically, File's drop() returns a Result, and the compiler enforces that we use it.
I hear linear types might also be coming to Haskell soon, which is pretty exciting. Such a thing is unfortunately impossible in Rust (though many languages can detect it at run-time).
[0] https://verdagon.dev/blog/higher-raii-7drl https://verdagon.dev/blog/higher-raii-7drl
- kitkat_new 4y agowhy is it impossible?
- verdagon 4y agoIn Rust, drop() can't return anything, it must return void.
- zozbot234 4y agoBecause panics in Rust can force-drop data as part of unwinding the stack. If Rust supported panic-free code easily, it could also add linear data which would eliminate the default Drop and replace it with custom, user-managed operations.
- Rusky 4y agoThere'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 ago
- orangetuba 4y agoHaskell and Rust both support linear types already.
- skitter 4y agoRust doesn't have linear/relevant types, only affine types.