Hacker News new | past | comments | ask | show | jobs | submit login

> But just multiple return values isn't enough for me - too much "if error return error" noise for my taste.

This is such a big deal, I don't understand how it's defensible. Code is read dozens of times more often than it's written. When code looks like:

    if val1, err := thingImActuallyTryingToDo1(); err != nil {
        return nil, fmt.Errorf("thing failed: %v", err)
    }

    if val2, err := thingImActuallyTryingToDo2(val1); err != nil {
        return nil, fmt.Errorf("thing failed differntly: %v", err)
    }

    if val3, err := thingImActuallyTryingToDo3(val3); err != nil {
        return nil, fmt.Errorf("thing failed again: %v", err)
    }
it's impossible to tell at a glance how the function is actually working. You have to parse out 90% garbage just to get to the details of what's really happening.

Worse is that it's never this "clean" and repeatable in practice. It becomes a bunch of subtly-different variants on that theme (append if the function wasn't an error, or do something different if it errored, etc.) that the actual logic of your function is obscured in a maze of error-handling.




In distributed systems (i.e. what Go was designed for), 90% of your actual logic is dealing with errors of different shapes and colors. How you handle that is what makes the difference between a toy and a reliable system.

Code doesn't become easier to read/understand by just tucking away 90% of it (the hard/interesting parts at that, mind you).


Dealing with errors should create noise in the code in proportion to the places where error handling needs to take action.

If 90% of your code really is unique, specific action to error conditions, then by all means, this topic isn't for you.

But if 90% of your code is "stop processing in this function, log the error, and pass it up the stack", then why not abstract that away and reduce the noise? (i.e. something like exceptions or monads or arrows or ...)


Yes, thank you. If you somehow have a problem domain where most of the errors you encounter can be gracefully (but uniquely) handled, then that's fantastic for you. But in virtually every golang example I've seen, you're just gift-wrapping the error with a little bit more context (or not) and returning it up the stack. In which case you've just replaced automatic, computer-executed exception handling with bespoke, artisanal, handcrafted exception handling for no gain and a hell of a lot of loss.


> it's impossible to tell at a glance how the function is actually working. You have to parse out 90% garbage just to get to the details of what's really happening.

After a while, you just learn to ignore the `if err != nil` and get on with your life. I mean, sure, it would still be nicer to have an abbreviation, but it's not like Go code is 90% `if err != nil` (as critics always try to frame), and when I read Go code, I'm most definitely not spending most (or any) of my time stumbling over them.


It's not 90%, but it seems like it has to be more than 50% because not only does every call require an error check but f(g(x), h(y)) has to be broken down and given three error checks.


Yeah. In my experience it's way closer than 90% than 50%. Even with one argument, function chaining is absurdly annoying. You can't just call f(g(x)), because you have to pull out the error check and do it manually.

And most of your code winds up doing error checks because if any call in the stack under a particular function produces an error, it usually winds up having to bubble the entire way up the stack.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: