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

Can anyone familiar with Go explain why not

  return sayThanks(thanksStr)
I've seen this "if err != nil" pattern before, but I can't help thinking that it's not necessary.

"return ret, nil" ignores err's value, which is nil anyway.

"return nil, err" ignores ret's value, but why? If the caller checks for err before doing anything with ret, it doesn't hurt having ret always passed up.

4 extra lines only to lose the value of ret in case of error.




You can golf it down to

    return sayThanks("thank you rsc")
without losing anything, but then it could just as easily be JS.


It's a joke about how every contrived Go example posted to the internet is in that vein. You wouldn't blindly pass something up the stack like that in a real application. Well, maybe if you hate other developers for some reason.


In this case, the if err != nil is completely useless.

Usually the pattern is used to perform better error handling (wrapping errors) or in case you call multiple functions that might return an error.

In this case, your suggestion is actually what I would expect to see


It's not needed if it's just on its own, but Go's error handling makes it necessary when chaining functions, which is why you see it so often.

Imagine in Java or Python or C# or ... many languages that use exceptions to handle errors:

    return a(b(c(arg)));
...where a(), b(), and c() can throw some kind of exception, so you don't have to handle them then and there. In Go there aren't exceptions, all error handling is explicit and handled conventionally by returning an error as the last (sometimes only) return value, which isn't composable, so you get:

    cVal, err := c(arg)
    if err != nil {
        return nil, err
    }
    bVal, err := b(cVal)
    if err != nil {
        return nil, err
    }
    return a(bVal) // the final call can be simpler
That's the minimum verbosity required. Since Go 1.13 (2019), they officially added the concept of "wrapped" errors (aka "cause" in languages with exceptions) so instead of returning err you can return errors.Wrap("error in the a-b-c function calling c", err). But nonetheless, _every_ level of the call chain has to wrap or pass on all errors with explicit code. Go does have panic() and recover() which allow for exception-like error handling but it's not idiomatic to use them for normal error handling, go wants that to be explicit.

As for why "return nil, err" rather than "return ret, err"? Because while the caller _should_ check for errors, sometimes they just don't.

    ret, _ := abc(arg) // just ignore the error
    ret.DoSomethingFun()
You as callee don't want to get the blame if you've _partially_ filled an struct because you returned early with an error, and it's then usable but causes a crash because it was partially initalised, because someone ignored the error they got when creating it. That hides where the problem really was. Better to return an empty value, default value or nil.


Thanks a lot for taking the time to explain!




Consider applying for YC's Summer 2025 batch! Applications are open till May 13

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

Search: