5 ms·
The article isn't really about any of that though. It's about a much simpler problem: how to produce error output that is useful to developers looking to fix a
by brazzy 6y ago
The article isn't really about any of that though. It's about a much simpler problem: how to produce error output that is useful to developers looking to fix a bug.
And I'm no Rust developer, but it looks to me like it basically demonstrates how Rust is an abject failure in that regard. The developer has to jump through lots of nonobvious hoops and choose between competing libraries to get anything useful.
Contrast that with Java, where any uncaught or logged exception prints a detailed stack trace and (usually) one or more useful error messages, by default, since day one.
This is a problem with very good known solutions, yet Rust seems to fail hard.
- kibwen 6y ago> Contrast that with Java, where any uncaught or logged exception prints a detailed stack trace and (usually) one or more useful error messages, by default, since day one. I think you're misunderstanding what the OP is trying to show here. If all you want is a backtrace, then Rust supports that out of the box. Here's an approximation of the full error message that you would see from the first example in the post: thread 'main' panicked at 'dumping failed', src/main.rs:2:5 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace The OP has omitted the next line, which tells you how to receive a backtrace. Backtraces are off by default in Rust because, unlike Java, Rust has a lightweight, C-style runtime that tries not to impose any runtime cost that the programmer did not ask for.
- ymbeld 6y agoI don’t get why this is off by default for debug builds though. Maybe that’s a separate concern.
- alpaca128 6y agoIn my experience enabling the backtrace is necessary in very few cases. I've defined a bash alias to save me a little typing in those situations. As it can be turned on persistently by setting a single environment variable I'd say it's a good middle ground.
- barrkel 6y agoIn other compiled languages, stack traces can be supported by looking up code references on the stack in a map of executable addresses to source code locations. Even in the absence of stack frames, the mere contents of the stack with lookups where possible is really useful, and usually more than enough. The cost is a little code to do lookups at runtime, and making the mapping data available (typically compressed and embedded in the executable). (Note that this isn't stack unwinding or exceptions. This is backtraces. Rust, like most languages which embed errors in return values, makes the developer do the stack unwinding manually.)
- _ek94 6y agoThat’s exactly how rust generates backtraces though. They just are not typically attached to errors.
- h0l0gr4ph1c 6y ago> And I'm no Rust developer, but it looks to me like it basically demonstrates how Rust is an abject failure in that regard. The developer has to jump through lots of nonobvious hoops and choose between competing libraries to get anything useful. As a rust developer, there are other ways to skin a cat, or an Error return as it were. For the std::net library (I've been using it when dealing with tcp/udp sockets), when a socket returns an Error, it uses std::io::Error [1]. This is basically a struct that implements the display and Error traits, it stores an enum inside of the types of errors that you may want / need to ignore/ handle. You don't technically need to use libs to do anything error related. This code has been round since Rust 1.0. Imho, this is kinda how Rust should tell people to make/handle errors. I like it. But I also have found rust enums to be extremely powerful in a lot of use cases. [1] https://doc.rust-lang.org/std/io/struct.Error.html https://doc.rust-lang.org/std/io/struct.Error.html
- jdmichal 6y agoI'd like to just point out that Java didn't have exception chaining until 1.4. And suppressed exceptions were added in 1.7 along with the try-with-resources construct. I know 1.4 was a long time ago, but it was 4 years after 1.2, which is what I typically consider the start of Java becoming a dominant language. I'm only posting this because I find a lot of people forgetting that Java has had a very long history at this point. And that many of the things we take for granted in the language today did not always exist. I still remember when generics were released. Get off my lawn.
- brazzy 6y agoOh, I've been around since the 1.2 days as well. Somehow, exception chaining didn't register as a big change when it happened. But yeah, incremental improvements have been pretty important as well.
- jdmichal 6y agoI agree regarding the chaining. I don't even remember thinking twice about it when it was introduced. But the ability to transform exception types without losing the original context and stack trace is actually a pretty big deal!
- ymbeld 6y agoIt took Java until Java SE 14 (last year) to produce NPE stacktraces which actually tell you which variable was null. At least in Rust third parties could have created a library to remedy a similar situation.
- jdmichal 6y agoFor whatever reason, it look a long time for parameters and locals to have a name in addition to a slot and a type in the JVM bytecode. Before that data was introduced, it was an impossible task. Also why things like de-/serialization frameworks required annotations on parameters duplicating the parameter name.