Engineering Blog

Never using named result paramater

In Go return or result parameters can have a named parameter. Having a named parameter eliminates the necessity of having a variable name along with a return parameter as the user can only use a return keyboard to return the result. When a result parameter is named, it’s initialized to its zero value when the function/method begins.

Here’s an example that uses a named result parameter b :

func f(a int) (b int) { 
b = a
return
}

In this example, we attach a name to the result parameter: b. When we call return without arguments, it returns the current value of b.

When to use named result parameter

When is it recommended that we use named result parameters? First, let’s consider the following interface, which contains a method to get the coordinates from a given address:

type locator interface {
getCoordinates(address string) (float32, float32, error)
}

This interface isn’t exported so the documentation is not mandatory. In the above code, there are two float32. It is difficult to finalize what this float32 means. Perhaps they are latitude and longitude, but in which order? Depending on the conventions, latitude isn’t always the first element. So, we have to check the implementation to understand the flow. In this case, we have to use the named result parameter to increase the readability of the code.

type locator interface {
getCoordinates(address string) (lat, lng float32, err error)
}

With this new version, we can understand the meaning of the method signature by
looking at the interface: latitude first, longitude second.

Here is another function that stores the Product type in the database.

func StoreProduct(product Product) (err error) {
// ...
}

Here, naming the error parameter to err is not helpful as it doesn’t help in improving the readability of the code. In this case, we should reduce the use of the named result parameter. So the use of the named result parameter depends on the context. We should not overuse it where it doesn’t help make code readable.

Also note that having the result parameters already initialized can be quite handy in some contexts, even though they don’t necessarily help readability. The following example is of io.ReadFull function.

func ReadFull(r io.Reader, buf []byte) (n int, err error) {
for len(buf) > 0 && err == nil {
var nr int
nr, err = r.Read(buf)
n += nr
buf = buf[nr:]
}
return
}

Here, using named result parameters doesn’t increase the readability. As both n and err are initialized to their zero value, implementation is shorter which may hamper the readability of the code. This function can be confusing for the reader.

One note regarding naked returns (returns without arguments): they are considered acceptable in short functions; otherwise, they can harm readability because the reader must remember the outputs throughout the entire function. We should also be consistent within the scope of a function, using either only naked returns or only returns with arguments.

So, using named return parameters with an interface may increase the readability of code with no side effects. But in method implementation, there are no specific rules. In cases where two parameters have the same type use of the named result parameter increase the readability. In other cases, they can also be used for convenience. Therefore, we should use named result parameters sparingly when there’s a clear benefit.

References:

100 Go Mistakes and how to avoid them, Teiva Harsanyi, Manning Publications Co

Previous Post
Next Post