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

Related Articles

24 Comments

  1. 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. 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;
    }

  3. 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.

  4. 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 ๐Ÿ˜€

  5. 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.

  6. 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.

  7. 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.

  8. 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…

  9. 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.

  10. 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.

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top button