> pushing humans a little more to care about errors
This is 100% a reason that I like using SNAFU. The term I use for this is a "semantic stack trace" — a lot of the time, the person experiencing the error doesn't care that it occurred in "foo.rs" or "fn bar()" or "line 123". Instead, they care what the program is trying to do ("open the configuration file", "download the update file").
When I'm putting effort into my errors, I basically never use `snafu::Location` or `snafu::Backtrace`. My error stacks should always be unique — any stack can exactly point to a trace through my program.
The problem with encoding only "what the program is trying to do" in the error is that it only helps users when it's an "expected" situation. For the "open the configuration file" example, it's usually something the user can understand and fix on their own: file is missing, bad permissions, etc.
But errors also need to be useful when reporting bugs to the author of the software. Error context and the error message can't always tell me what specific call stack caused the error, and I will most likely need that when tracking it down. I hesitate to want a backtrace included, as generating those is usually bad for performance, but I think SNAFU's "location" concept is a great compromise.
I see your reply further down about "Users rarely have good access to the developer team", but I just don't buy that line of reasoning. As a developer, I both want to make it as easy as possible for my users to solve problems on their own (so: informative error messages that give the user a good chance of figuring it out themselves), but I'm only human, and I know all the software I write has bugs. So I want my error reporting to have enough information such that the user can contact me and give me as much information as possible about the error, without needing a lot of back and forth, or without me needing to ask them to run things in a debugger or use a special build.
And on top of that, a lot of code is written inside a company, either as a network service, or tooling used only by people inside that company. The developers are very close to the use of that code, and having a lot of information come with errors is essential.
> My error stacks should always be unique — any stack can exactly point to a trace through my program.
That seems like more effort expended when using `snafu::Location` would suffice, without doing extra work that is IMO useless. I'd rather concentrate on other things and have my tools do fiddly, repetitive work for me.
But... It's not the user that is seeing this, it's the developer. You catch at the top of your event loop and you log the stack trace to some place that can be reached by the dev team, be it Jira, some crash reporting tool, etc.
Yeah, but lots of diagnostic work is done by end users in the real world. Users rarely have good access to the developer team, if the team even still exists. Usually there are layers of insulation that mean your problem might be looked at in a few weeks or months only if the company thinks it might be interesting. Meanwhile you have your problem to fix and it is off to stack traces and access logs to try to figure out what went wrong. Maybe some library updated. Maybe there was a permissions change. Maybe some policy change at the OS level. Maybe some external resource went away or changed syntax. It is up to you as the end user to figure it out and fix it, or at least figure out a unique enough error message that you can Google to find someone else with the same problem.
There is nothing more frustrating than a dialog box that says "An error occurred" and then the program shuts down. Frankly I'd rather it crashed hard, at least then I might have some evidence to sift through in the blast zone.
>Yeah, but lots of diagnostic work is done by end users in the real world. Users rarely have good access to the developer team, if the team even still exists.
And hiding details prevents them from being able to know if error X is different from error Y, yes.
It's an unhandled error at that point. You do not know what is relevant, essentially by definition, because otherwise you would have handled it.
Display messages are almost completely unrelated to error handling, and have almost completely unrelated needs. If you decide to combine them, I'm pretty convinced that it's ALWAYS better to show ALL context somewhere, because otherwise troubleshooting frequently becomes impossible. It doesn't have to be a megabyte of stack trace info in a dialog box shown all the time, save it to a file and link to it or something.
When presented with a bug from the field, I also care about finding the path through my code where it occurred, but rarely do I need to know that `foo` called `foo_with_caching` called `foo_with_caching_recursive`. When reading a backtrace, I skip over amounts of "implementation details" to get a big picture. For me, the exact functions / files / line numbers are not relevant, doubly so if I'm working in a situation where the error message isn't tied to a specific git commit and the functions/files/lines have moved over time.
To reiterate my point from above though, my error stacks are all unique — seeing the stack will point me to an exact line in my code where the error occurred, even though I don't include function/file/line as-is.
I don't really agree. Well, I do agree that often if I'm looking at a backtrace, I will be skipping over a lot of stack frames to find the "simplified" path that still is most useful.
But functions? Yep, absolutely need them. Files? Not quite so much, since it's rare that I'd use the same function name between files. (But sure, throw it in anyway.) Line numbers? No, those can be a big help. If a user reports an issue to me, the first thing I will ask them (if they didn't fill out the issue template properly) is what version they're using (and what git hash, if they've self-compiled from a random git checkout). So I can check out the same version on my laptop, and having a line-accurate trace can be very helpful.
> To reiterate my point from above though, my error stacks are all unique
To reiterate mine, my error stacks often aren't unique, and crafting them such that they would be seems like pointless make-work when there are tools can make it so I don't need to care about this.
I really don't get this resistance against including this information. It adds little to binary size and remove little from performance, so why not include it? I agree that backtraces do add a lot to binary size and can murder performance, but this "StackedError" concept with function/file/line information seems like essentially the perfect compromise. Just... include it, and stop worrying about it.
This is 100% a reason that I like using SNAFU. The term I use for this is a "semantic stack trace" — a lot of the time, the person experiencing the error doesn't care that it occurred in "foo.rs" or "fn bar()" or "line 123". Instead, they care what the program is trying to do ("open the configuration file", "download the update file").
When I'm putting effort into my errors, I basically never use `snafu::Location` or `snafu::Backtrace`. My error stacks should always be unique — any stack can exactly point to a trace through my program.