Linux
Why I Prefer Exceptions To Errors
Recorded live on twitch, GET IN
### Article
By: Philipp Fent |
### My Stream
### Best Way To Support Me
Become a backend engineer. Its my favorite site
This is also the best way to support me is to support yourself becoming a better backend engineer.
MY MAIN YT CHANNEL: Has well edited engineering videos
Discord
Have something for me to read or react to?:
Kinesis Advantage 360:
Get production ready SQLite with Turso:
[ad_2]
source
Whoever came up with the idea to display your keystrokes is a genius. Literally learning vim by osmosis thank you
so Prime doesn't know what a RAII is
Double standards. One second he says NASA are cool because they crash programs on bad state, and then he defends how Rust allows UB in release mode, which doesnโt crash your program, but silently uses some undefined state. Which is entirely contradictory to the reasons of using error values in the first place
2:29 Better version:
int safeRatioN(int numerator, int divisor, int defaultValue) {
int result = defaultValue;
if (divisor != 0)
{
result = numerator / divisor;
}
return result;
}
int safeRatio0(int numerator, int divisor) {
int result = safeRatioN(numerator, divisor, 0);
return result;
}
int safeRatio1(int numerator, int divisor) {
int result = safeRatioN(numerator, divisor, 1);
return result;
}
This time I completely agree xD
One (somewhat) nice thing about exceptions is that you can just ignore any exceptions except at the very top level in deeply nested code. If I've written some recursive descent parser in a C# GUI app where uncaught errors are verboten, it's liberating to just ignore 90% of errors (other than null deref) in the code for the recursive descent parser and only include try/catch/finally in the top-level user-facing code for something like a form. As others have noted in the comments, C# handles unwinding the stack, deallocation of memory, etc. for free.
OTOH, one nice thing about error-returning (or even the super-old C paradigm of setting an errno) is that it's a convenient paradigm for some process like a JSON parser that is progressively constructing something when a syntax error halted parsing, and you want to be able to show the user the (incomplete) result that had been produced before interruption by the error. You can't really use exceptions if you want to do this, unless you bind the state being constructed to the object that's constructing it.
when catching exceptions, you catch any and every possible exception and can handle them accordingly. you can even then specify more detailed exception coming up while debugging – rather than defining an error as a value. when you have to first asign the possibles errors, i guess you miss more than when catching any exception
exception handling is even build in, i want to divide by zero, i get an excepton without any work and can handle it. i can catch any Exception and log it, check the logs, find an divisionbyzero error, handle that exception specifly (ask for another input or check datasource whatever) and still catch any other exception possible, to be found in the log then
if i have to first implement a check for dividing by zero, return that as errorAsValue to then do a checking what errorAsValue i recieved to then handle it… too much work and not much of a benefit in anyway
throwing exceptions (wenn something program-breaking happens!), catching it and handle it – clean
talkin c# here
most propably not my best english today ๐
12:32 you know by convention, by making sure that your code maintains "strong exception safety" at all levels. This does manifest in simpler code overall (no more if nil != err after each function call) at the cost of being meticulous about meeting the strong exception safety level which unfortunately there isn't good tooling for iirc. When working on a larger project, asserting that the exception safety holds becomes difficult. For single maintainer who is used to it, it's easy, and from experience does make error handling easier.
Regarding C++ cleaning everything up for you on exception, it's not true that everything gets cleaned up. Like you said, if you directly use new or malloc to allocate some memory on the stack, that memory is just leaked unless you've stored the address in a variable with a scope at least as high as the catch block that matches your thrown exception, but if you follow the core guidelines, then you'll never be using new directly (except possible in a container, in which case the destructor should be responsible for calling delete). What is guaranteed is that all objects which go out of scope will be deconstructed in the correct order, which means that as long as your resources are being managed by an owning object, such as std::unique_ptr (which generally will be optimized into just a pointer anyway) or std::string, it will be automatically freed.
Again the Erlang let it crash model mixed with prolog roots is the best of both worlds.
My favourite thing about exceptions is that they allow you to define the place they should be handled.
Say we have function A, B, C that calls D and then E. In E we do a network call that can fail. What happens when E fails is slightly different in A, B and C. Exceptions allows us to pass through D and keep things generic.
Granted the issue I find is more pressing is when a Junior dev doesn't know D can fail and uses it in function F. Then D fails, F doesn't handle it and F causes the entire system to crash.
This issue doesn't really go away with C style return values. It could be argued to be worse since it may cause F to fail in an unrelated way.
I think I get the point. You can always wrap a large clusterfuck with try catch and at least maintain a non-crashed state
In other words it is micromanagement vs macromanagement.
Exceptions are certainly more convenient than checking a result of every operation. But you can use '?' to reduce efforts.
Comparing C++ with exceptions to other languages while omitting RAII idioms is dumb.
If you are considering OOM, you are already in a specific type of system, where you must control resources usage. This canbe fone on non-real-time-operating-systems ONLY out of process. You can not control your universe from inside your universe, because you can not proove its complete correctness from INSIDE YOU UNIVERSE. That is your system, or smaller, your process, can not decide about its complete correctness. You can do that only partially. It comes form second Gรถdel's incompleteness theorem…
Exceptions make for easier lazy user facing error messages, but they are still a lazy dev life hack
"I can catch an exception 4 times faster! 1microsecond instead of 4!"
TypeScript recently decided that they won't add any sort of "checked exception" kind of system to their type system, at least for now, and one of the reasons they cited for this was that the JavaScript community, as a whole, does a really, really bad job at documenting what functions can even throw (so how could the community ever hope to add accurate type definitions relates to errors for libraries when the information the community is trying to document in the types is entirely undocumented to begin with). Even Node itself does a really poor job at documenting their exceptions – want to know what kind of error gets thrown if a file is not found? I can't find that anywhere in their documentation – I have to go and attempt to open a non-existent file and see what the error looks like to know what to look for in a catch block.
My point is – languages that have errors as values also tend to have their errors very well documented, because it's literally part of their type signature, while languages that have thrown exceptions tend to be much more lax in their documentation, which in turn makes it that much harder to write any kind of robust code in these kinds of languages. It doesn't have to be that way, but that seems to be the common pattern.
in my experience devs in many cases do a bad job at error as value and leave out critical debug information that i would get from exception otherwise
There is a time to use exceptions and a time to pass back errors. Neither time is 'never' nor 'always'.
Diet Thor is yelling at clouds again.
Totally agree. Exceptions are just a bad idea for a number of reasons. The worst one being that you newer know which exceptions can be thrown even if you read the doc. And apparently it is impossible to do exception handling correctly in C++. Not the sort of code I want to write. Classes has also turned out to be a bad idea and the approach taken in Go and Rust is much better.
My approach: exceptions are for exceptional cases, result type with errors – for expected failures like user input validation, not found, unauthorized, etc.