12

What's your opinion on the error-value vs try-catch debate?

I'm usually on the error-value side of things.
Its the preferred error-handling in Go and the pretty much only decent solution in C.
Also, frequently thrown exceptions seem to impose a larger overhead than the constant checking of the error-value.

Comments
  • 6
    In C, you can use setjmp/longjmp if you want exception style error handling. The main drawback is that it makes the control flow harder to understand.

    Checking the return value works regardless of the control flow and where the function is in the stack, but it has to be implemented in every function along the chain.
  • 1
    I lean railroad. How I get there is of little importance to me.
  • 2
    Error value is better for me because there is always room for error, for example a non critical function that does something that I need but still returns an error. I don't need to handle it, I can just skip it
  • 3
    I just use try catch cause I usually mess up the other way for some reason.
  • 2
    It depends. In Python I use exceptions all the time. In C++ I hardly ever (never in some codebases) use them.
  • 1
    Used to using Exceptions. I like the error-value pattern and think that is easier to understand as well
  • 7
    Quite honestly, try-catch

    The few times I played with Go I got severely annoyed by the fact that I have to check the err variable every 4 lines, and it just looked messy
  • 1
    On Windows C has __try __except blocks
  • 4
    I prefer try catch, but I'll generally go with whatever the convention is in the language I'm working in.
  • 1
    > Also, frequently thrown exceptions seem to impose a larger overhead than the constant checking of the error-value

    Not necessarily. The JVM, for example, optimizes away the stack trace of frequently thrown exceptions, under the assumption you're using it for control flow.

    As for your question, I generally use what's idiomatic in the language and lean towards railway programming using an Either type. I find both try-catch and railway programming lead to very readable code.
  • 8
    Both are shit.

    This comment was sponsored by Option() gang.
  • 1
    Erm ok, something more thoughtful: for me the best example for exception usage is in some sort of parser code that reads some nonsense syntax. Typically compiler doesn't bail out after first error so using exceptions you can throw one once you encounter bad syntax and catch the exception in the main loop just before the code that reads new line.

    Underneath C++ still uses setjmp longjmp as FastNop mentioned. And those two functions aren't too expensive, but they get very expensive if you call them a lot (e.g. in a loop).
  • 2
    Man fuck those primitive tools. Try catch is bulky and not elegant at all, error values seem like a workaround and only look clean in C when you got proper documentation which is almost never the case.
  • 2
    Error value is the best, except for really unintended problems (aka fix asap) like array out of indices. It should throw but not been catched.
  • 3
    It depends.
    Returning an error state is the functional pure way of doing it. Exception handling also isn't free, wich might be relevant in performance critical code.

    But exceptions really shine when it comes to generic exceptional error handling (hence the name). Sprinkling the code with invariant checks is way more feasible than proving code to be correct.
    Handling that violations requires a human to actually find the cause and fix it. And when you already know, that an invariant does not hold anymore, there really is not point in continuing processing that data... So just throw a BugFound and let some wrapper higher up the stack log it.

    They also can be used to get one more return type in languages wich don't support union types (optional/nullable does not count).
    Python does so with its exception on iterator exhaustion.

    The gist is: When the result is to be handled by the call site, return it. Otherwise throw it. Just never continue with data you know is wrong...
  • 1
    @yellow-dog
    The option type isn't the correct way to handle errors. Use the result type for that:
    https://en.wikipedia.org/wiki/...
  • 1
    I usually prefer try catch and I generally add custom exceptions so i know the exact point in the chain where it crashed...it's also easier to write accurate error logs this way (for me at least)
  • 1
    Dunno how Go works, but in languages like Java and similar I generally prefer unchecked exceptions.

    I tend to go crazy with exceptions in class internals, and catch them in common places, usually public facing methods.

    Doing this, I de-clutter class internals, since I avoid endlessly propagating error return values or checked exceptions.
  • 1
    @bittersweet I am interested in your opinion on this in laravel projects.
  • 3
    @Wombat Throw your laptop in a fire, buy a new one, install Rust, use something like Rocket.rs.

    Serious answer: I avoid Exceptions in PHP like the plague.

    A language like PHP doesn't lend itself well to monadic wrappers (option/either types), but I still try to use a pattern like that as much as possible -- Exceptions are like GOTO, and uncaught Exceptions halt the fuck out of shit in undesirable ways.

    So I tend to return a DTO which encapsulates the state as best as I can within the limits of PHP's type system.

    But in general, my opinion on try/catch/exceptions vs error value:

    Neither.

    Go's Error value is a cheap weak-ass alternative to full-fledged Option/Either monads or constructable algebraic data types.

    So fuck PHP, fuck Go, fuck Python and Java -- long live Haskell and Rust. 😁

    (Several modern languages like Kotlin & Swift have tolerable features as well)
  • 0
    @Oktokolo a result is an option
  • 0
    @yellow-dog
    The option type can be modelled with a result type having the "error" constructor only accept a unit/null/none/nil. But you can't model the result type using an option type.

    The option type is good for when no metadata is needed for handling the error case.
    The result type is good for when the name of the error (or more/other meta/context data) is needed for handling the error.
  • 2
    I would really advise everyone to at least read how Rust does this:

    https://doc.rust-lang.org/book/...

    Or, if you prefer Kotlin:

    https://kotlin.christmas/2019/17
  • 0
    i like error values
  • 0
    Dunno, both, depending on the function Im writting. Some make more sense with try-catch to handle stuff, but sometimes I want the error to propagate better and error value is more helpful..
Add Comment