How to handle errors when they are NOT the only value returned by a function?

Viewed 88

I have created a function to handle errors that looks like this:

func handleErr(e error) {
    if e != nil {
        log.Fatal("Error:", e)
    }
}

For functions that only return an error, I can do the following:

handleErr(os.Chdir("Documents"))

However, for functions that also return other values and not only an error, I have to spread my code over two lines, like this:

s, e := os.Getwd()
handleErr(e)

Is there a way to condense the above two lines into one?

1 Answers

Please note that it's not possible to uniformly handle the error and return a dynamically typed value at the same time. handleErr() could only return a value of type interface{}, further type assertion would be needed to extract a concrete type from it. As noted by mkopriva's comment, generics is needed to make the return type "dynamic".

The below answer only handles the error, but discards the other return value(s).

If you can modify handleErr()

Add another parameter to handlerErr() of interface{} type. Any value is assignable to interface{}:

func handleErr(i interface{}, e error) {
    if e != nil {
        log.Fatal("Error:", e)
    }
}

Lets use this example function:

func foo(fail bool) (int, error) {
    if fail {
        return 0, errors.New("fail")
    }
    return 0, nil
}

Testing it:

handleErr(foo(false))
fmt.Println("First is OK")
handleErr(foo(true))
fmt.Println("Second is OK")

Output (try it on the Go Playground):

First is OK
2009/11/10 23:00:00 Error:fail

handleErr(foo(false)) is possible and is valid, because Spec: Calls:

As a special case, if the return values of a function or method g are equal in number and individually assignable to the parameters of another function or method f, then the call f(g(parameters_of_g)) will invoke f after binding the return values of g to the parameters of f in order. The call of f must contain no parameters other than the call of g, and g must have at least one return value. If f has a final ... parameter, it is assigned the return values of g that remain after assignment of regular parameters.

If you can't modify handleErr()

You can write a helper function which reduces 2 return values to one:

func reduceTwoParams(i interface{}, err error) error {
    return err
}

You may use this with any functions that return 2 values where second is error, because all values are assignable to interface{}.

Testing it:

handleErr(reduceTwoParams(foo(false)))
fmt.Println("First is OK")
handleErr(reduceTwoParams(foo(true)))
fmt.Println("Second is OK")

Output (try it on the Go Playground):

First is OK
2009/11/10 23:00:00 Error:fail

If you want to handle functions with 3 return values, you have to write another helper:

func reduceThreeParams(i, j interface{}, err error) error {
    return err
}
Related