Quidest?

Modifying result parameters after exit in Go

· Lorenzo Drumond

The defer keyword is useful for clean up operations. However sometimes we want to be able for the deferred call to modify the return value of the enclosing function.

Suppose we have some function that writes data to a file, and returns a error result to indicate whether is succeeded.

We want to defer closing the file. However, the closing operation itself could fail. In that case we need to return error. But since the error happens in the deferred function, the return value has already been set to be nil:

1... // we open f
2defer f.Close()
3... // write to f
4return nil

We can defer any function call. So instead of deferring f.Close() directly, we could defer a wrapper function literal:

1defer func() {
2  closeErr = f.Close()
3  if closeErr != nil {
4    fmt.Println("Error")
5  }
6}()

However we can do even better: if we name this function’s error result parameter err, then it’s declared inside the function. A function literal is a closure on the function’s variables, therefore we can access err from inside the closure:

1defer func() {
2  closeErr = f.Close()
3  if closeErr != nil {
4    err = closeErr
5  }
6}()

This will modify the function’s result after it exited, but before it returned

References

#expression #values #defer #programming #type #bubble #functions #body #closure #parameters #declare #signature #leak #first_class_citizens #tuple #literals #golang #variadic #stack #list