Confusion about use of named return in a Dig Deeper

func FromRNA(rna string) (proteins []string, err error) {
	for i := 0; i < len(rna); i += codonLength {
		codon, err := FromCodon(rna[i : i+codonLength])
		if err == ErrStop {
			break
		}
		if err == ErrInvalidBase {
			return noProteins, err
		}
		proteins = append(proteins, codon)
	}
	return proteins, err
}

The named err in the return values is a different err from the one inside the for loop. Is this idiomatic?

A named return variable is initialized with its zero value, which can be changed in the course of the function. If it is an int, it is initialized with 0 and could be changed to 1 or 1000 in the function, which is similar to what is happening with err in fromRNA.

As to whether it is idiomatic, it depends on who you ask. There are people who would disagree with its usage here.

Sorry for all the edits, on my tablet which has a mind of its own.

Related: Effective Go: named results

In general, I prefer explicit over implicit and generally stay away from named results. I much more prefer an explicit return proteins, nil when there’s no error. I think this is also the standard pattern.

Nothing wrong with being explicit, although programming seems to be moving more toward the implicit (I’m thinking of type inference and chaining functions instead of using explicit steps in a loop, offhand.)

I used to return nil until a young mentee said “why do that when the err is already initialized to nil?” And I thought, okay, the younger generation is seeing something I didn’t, so, fair enough.

What is standard doesn’t enter so much into the equation for me, as I think of what Eric S. Raymond wrote long ago in The Art of Unix Programming

Rule of Diversity: Distrust all claims for “one true way”.
Even the best software tools tend to be limited by the imaginations of their designers…
Therefore, the Unix tradition includes a healthy mistrust of “one true way” approaches to software design or implementation.

That said, if anyone wants to change it more to their liking, I have no objection. No “one true way” works both ways, so to speak. :slight_smile:

To echo statements earlier it’s sort of split in the community. Most people (myself included) now believe that explicit returns as defined in the code are most clean, with named returns simply a syntactic sugar that can lead to confusion. The official docs from the go team do prefer named returns, but I think these are used far less than the doc implies.

Personally I always recommend an explicit definition within the function instead of named returns!

I don’t think @glennj’s question is about the usage of named returns in general; it’s more about the fact that the err variable inside the for loop on line 3 is a new variable that shadows the err variable in the named return. Assigning to the err in the for loop will not affect the named return. I find this to be confusing and error-prone.

If you want to assign to the outer variable, you’d write something like this:

var codon string
codon, err = FromCodon(...)

Yup, variable shadowing is an issue that can be confusing, especially in a large function.

Here, I like that the interior err has no effect on the named return err, since we want to return nil for ErrStop. So, to me, it has a kind of elegance, but I also see it how you’re saying, which is certainly a legitimate concern.

What got me at first was

        if err == ErrStop {
			break
		}
        ...
    }
	return proteins, err

“why isn’t it returning the ErrStop error?”

It looks like the link to the switch approach for Protein Translation is not working.

@ErikSchierboom, could you take a look at the switch approach for Protein Translation on the Go track?

Edit: My mistake in the link. Will fix…

1 Like

I like named return values. But they should be used, which isn’t the case in the example code.

Shadowing can be a big problem, as well as long functions, to identify the result. For clearity, working without named return values is preferred. Also have in mind, what you expect is in the so initialized variable. I saw often that its type is a slice, but should have been empty at the end of the function because of conditions. But of course, the result is nil. Get’s some confused.

Implicit code is great, like you don’t need declare the types everywhere. But those implicit code has a much smaller scope.