Earlier quoted context omitted.
Which already exists in Rust in the form of... wait for it... the Drop trait. It's the same thing.
The difference is that Go's `defer` is explicitly written out in the relevant scope, while Rust's `Drop` is implicit and defined elsewhere.
The Pain of Real Linear Types in Rust
51–60 of 82 posts
Re: The Pain of Real Linear Types in Rust
#52A lot of the awkwardness that the author describes comes from destructors, which Rust has taken from C++. In fact, Rust has even inherited the incoherence between destructors and exceptions from C++, due to the lack of a solution to the double-throw problem and the need to write unsafe code that is correct in the face of unwinding. The 'dropck' pass is one of the corners of the language that has no precedent in a typ…
Destructors seem to be a pain point for functional programming people. They're inherently imperative; they don't return anything because they have no one to return it to. The "unsafe code" problem comes mostly from backpointers. If you have a data structure with a doubly linked list, and the forward pointer and backpointer are both pure references and can't be null, no order of destruction is strictly valid. You can'…
There are many more patterns where that came from, and you don't want to teach the compiler about all of them. I don't think there's anything wrong with having a lower-level "unsafe" mechanism to let you use the language itself to build new types of structures that then provide a safe interface.
As a random example, consider the rust "intrusive-collections" crate (https://crates.io/crates/intrusive-collections), which provides the kind of "no extra pointer" linked list where you can embed a list head (or multiple list heads) directly in your structure. I don't think every such crate should have its functionality native in the compiler.
Re: The Pain of Real Linear Types in Rust
#53Earlier quoted context omitted.
Right or wrong, simply saying something is poorly named doesn't show that someone is hostile towards academia. By that standard, most of the academics I know would be hostile to academia, since they invariably think something in their field has a bad name.
I'm just miffed that they're complaining about names that are actual words. How would you like if they were all named after their discoverers, and therefore an a priori undistinguished mishmash of proper names? (cf. separation axioms[1]) [1]: https://en.wikipedia.org/wiki/Separation_axiom
oh, and:
The first step towards wisdom is calling things by their right names. —Anonymous Chinese Proverb
Re: The Pain of Real Linear Types in Rust
#54Earlier quoted context omitted.
Nobody's talking about semantic simplicity; we're talking about developer ergonomics.
If you take the view that code is read more times than it is written (which is lightly amusing given the topic of this thread), then shouldn't you optimize for the ergonomics of reading and understanding code that is already written rather than writing it? I don't see how Rust's choice is defensible from that viewpoint. If I quizzed actual Rust users (rather than the language developers that are posting here) about t…
Re: The Pain of Real Linear Types in Rust
#55Earlier quoted context omitted.
Friendly challenge (because I agree with you, but constantly run into limitations): I loop over strings a lot. Can I fit them into a nice recursive structure without runtime overhead? Bonus round: My loops over strings often aren't straight-forward one-byte-at-a-time iterations. Sometimes my loops look at 8 or even 16 bytes in a single iteration. How does that fit in with more sophisticated types like you're describi…
In practice, probably not. In theory, there's no reason one couldn't compile a linked list in source to a flat array at runtime if the access pattern was right (and linear types should make that kind of optimization a lot more practical. This might even be something one could implement "in userspace" in a language with linear types - like a safe version of an iterator. Certainly I'd be excited to try - I'm not claimi…
I wonder what the upcoming linear types work will do.
Re: The Pain of Real Linear Types in Rust
#56Earlier quoted context omitted.
Destructors seem to be a pain point for functional programming people. They're inherently imperative; they don't return anything because they have no one to return it to. The "unsafe code" problem comes mostly from backpointers. If you have a data structure with a doubly linked list, and the forward pointer and backpointer are both pure references and can't be null, no order of destruction is strictly valid. You can'…
> Maybe forward pointer/backpointer pairs need to be a language level concept. The compiler needs to know that the forward pointer and the backpointer are in a relationship. The pair needs to be manipulated as a unit. You have to have mutable ownership of both references to manipulate either. The borrow checker and destructor ordering need to understand this. There are many more patterns where that came from, and you…
People used to code like that, mostly in assembler and sometimes in C. It's not necessary for functionality. It's just an optimization. One that needs to be justified with benchmarks. Also, it's not at all clear that use of that module is safe.
I'm beginning to think there's a cult of l33t unsafe Rust programming, where people who write unsafe code think they're cool. I used to say that the way to cure new programmers of that is to put them on crash dump analysis for a few months. After they've found pointer bugs in other people's code, they'll have a better sense of why pointer safety is important.
Re: The Pain of Real Linear Types in Rust
#57A lot of the awkwardness that the author describes comes from destructors, which Rust has taken from C++. In fact, Rust has even inherited the incoherence between destructors and exceptions from C++, due to the lack of a solution to the double-throw problem and the need to write unsafe code that is correct in the face of unwinding. The 'dropck' pass is one of the corners of the language that has no precedent in a typ…
Destructors seem to be a pain point for functional programming people. They're inherently imperative; they don't return anything because they have no one to return it to. The "unsafe code" problem comes mostly from backpointers. If you have a data structure with a doubly linked list, and the forward pointer and backpointer are both pure references and can't be null, no order of destruction is strictly valid. You can'…
Destructors seem to be a
pain point
The problem is not so much typing as such (things that don't return anything but terminate -- as destructors do --
can be typed as Unit) but rather to find a good trade-off between
expressivity of the language and simplicity of the typing system.Basically explicit destructors mean the typing system needs to track lifetimes and ownership in some form or shape. There seem to be two main options.
- Simple lifetime/ownership scheme, but then you need a garbage collector anyway, and that it's mostly pointless to have explicit destructors. Just let every variable be cleaned up by the GC makes for a simpler language (under the hood clever escape analysis might be used for stack allocation of variables that don't escape their activation context).
- Avoid a GC, but then you need a complex typing system with unique owners to have any chance at expressivity (and you still need unsafe blocks and reference counting). This is Rust's choice.
Another issue is how consistently to combine destructors with other effects, in particular exceptions.
Pointer/backpointer pairs
need to be a language level
concept.
As "JoshTriplett" also suggests, this is certainly an interesting idea, but I don't think a compelling choice has been found yet.Re: The Pain of Real Linear Types in Rust
#58A lot of the awkwardness that the author describes comes from destructors, which Rust has taken from C++. In fact, Rust has even inherited the incoherence between destructors and exceptions from C++, due to the lack of a solution to the double-throw problem and the need to write unsafe code that is correct in the face of unwinding. The 'dropck' pass is one of the corners of the language that has no precedent in a typ…
And Í talk from experience.
Back in the early 2000, I modified both MS VS runtime and gcc to be able to safely throw from destructors. Note to doubters that Java allows such double-exception cases and gcc already had code back then to deal with the Java case.
The way to do it is to implicitly assume that every destructor ran during stack unwinding has a try/catch surrounding it. This way, a first exception can be thrown from a destructor, but all exceptions that ultimately escape a destructor invoked during unwinding gets eaten. (Note: you can still provide your own explicit try catch in a destructor if you care about it.)
My experience with this tweak was that the horror story people come up with to reject this approach is unfounded. Here are the reasons:
1. The actual case of double-exceptions are very, very rare.
2. In the case that do arise, the second exception is often either a consequence of the first (for example, trying to access a DB were teh first exception was a failure in some DB code) or the exact same (for example running out of memory).
3. In my experience (although, since the 2nd exception is lost, I cannot actively prove this), the first exceptionis the relevant one. This is especially true due to point #2.
4. In my experience, code that care about the exact type of exception is most often either wrong or misguided. This is because such code assumes complete prescient power over what exceptions can be thrown.
5. In my experience, catching exceptions is 99% done in the top-level message or task dispatching, which doesn't care about the type of exceptions or how many occured: you just abort the operation and do some logging.
6. The fact that double exceptions are handled gracefully informs your design, which builds up and reinforce all previous points.
I once had discussion on this in the 90s in comp.lang.std.c++ and comp.lang.c++. People would not listen.
Note: to do it with STL, you do have to add try/catch within destroy() calls within containers to be able to destroy all items.
Re: The Pain of Real Linear Types in Rust
#59A lot of the awkwardness that the author describes comes from destructors, which Rust has taken from C++. In fact, Rust has even inherited the incoherence between destructors and exceptions from C++, due to the lack of a solution to the double-throw problem and the need to write unsafe code that is correct in the face of unwinding. The 'dropck' pass is one of the corners of the language that has no precedent in a typ…
Double-exception handling during stack unwinding in C++ is the thing I disagree most with. And Í talk from experience. Back in the early 2000, I modified both MS VS runtime and gcc to be able to safely throw from destructors. Note to doubters that Java allows such double-exception cases and gcc already had code back then to deal with the Java case. The way to do it is to implicitly assume that every destructor ran du…
Re: The Pain of Real Linear Types in Rust
#60The author tries too hard to avoid using the word "object". "Must use" objects don't seem to be all that useful. More justification is needed. Is the author thinking of Javascript-like callback approaches, broken "promises", and such?