
Benefits of named return values in Go - y4m4b4
https://blog.minio.io/golang-internals-part-2-nice-benefits-of-named-return-values-1e95305c8687
======
edsrzf
I normally hate it when people immediately trot out the old "premature
optimization" quote, but it really applies here.

Please don't go around naming all your returns just because today's compiler
happens to generate better code with them. This is a compiler issue that I'm
confident will be fixed one day, especially if you do the right thing and file
an issue.

But by all means, if you're profiling and your inner loops are actually slowed
down by this, then make the change. And add a comment so that someone might be
able to change it back some day when the compiler's improved.

~~~
obstinate
I dunno. A 30% code size win is non-trivial. I'm all for filing an issue first
and seeing how likely it is that there is uptake from the dev team and desire
to fix the problem. However, if no fix is forthcoming . . . code size has
fairly well known effects on performance.

~~~
gizmo686
A 30% code size reduction in code that does little other than construct and
return a value. I have certainly seen individual _functions_ where this is the
case, but across an entire program, you will not get anywhere near 30% size
reduction.

Having said that, this is certainly something that should be fixed in the
compiler.

On a related note, in the final assembly, the compiler could also have
optimized the 4 RETs into 1, then optimized away all of the conditionals,
turning the sample code into the equivilent of "return objectInfo()"). Of
course, in a real example, these optimizations would not be possible; but they
do show that these reduced cases are not the best way of benchmarking
performance.

------
013a
I'm not the most proficient Go developer, but aren't the two examples doing
two different things?

In the first way, each branch allocates its own objectInfo struct. In the
second way, all the branch exits share the same single objectInfo struct which
I assume is implicitly initialized to the zero value by the compiler.

Functionally these are the same, but couldn't you achieve the same results
without named return values by just allocating a single objectInfo at the top
of the function and returning it?

~~~
fwessels
Yes, you can, but just naming the return variable takes care of this.

------
KirinDave
I look at these result functions and all I can think is, "Wow, it must be
really delightful when you get a zero record back and what to know why your
parser has a bug." I really hope these are didactic in nature and not a
representation of industry best practice.

Why not just declare a record in scope and return that? Why rely on a sneaky
little piece of syntax tucked away in the return value? Aren't gophers
supposed to be all about a regular language with few surprises?

~~~
cyphar
> Why not just declare a record in scope and return that? Why rely on a sneaky
> little piece of syntax tucked away in the return value? Aren't gophers
> supposed to be all about a regular language with few surprises?

It's not a sneaky piece of syntax, in fact it is required to use that syntax
if you want to reference or modify the return value of a function in a
deferred function call.

I don't like the syntax and hate that Go forces you to use it in the above
case, but it's definitely not sneaky syntax. Any regular Go developer should
be expected to know about this construct.

~~~
KirinDave
If you have long function and the addition of a single character up top at the
right changes the behavior of the return keyword?

I've hated this feature since I learned about it. Its existence is one of the
many reasons I dismiss arguments about Go being easy to read.

------
cyphar
This is possibly one of the worst reasons to use named return values. To be
honest, I've always disliked them because they make `return` magical since you
now have to read through the whole function twice to make sure that you know
what is actually being returned. Luckily you _can_ do explicit returns with
named returns, but then it becomes confusing if you have non-explicit returns
in the same function.

In my mind there are only two reasons to use named returns. The first is when
writing interfaces, and you want to document the returned values in a nicer
way (in addition to the godoc). This is mostly a taste thing and is not
required.

However, the second one _is_ required by the language and that is deferred
function calls that interact with the return value of a function. If you want
to have a deferred function call that does some cleanup but has to check the
error value of the function (for example a cleanup that only runs if an error
occurred) then you have to use named return values. If you want to have a
deferred function that _changes_ the return value of the main function then
you also need named return values. This is a fairly annoying requirement of
Go, but I understand why they felt it was necessary to do things that way to
make it feel more explicit.

Other than that, in general named returns make functions harder to read (in my
opinion). In a similar vein, I really don't like Ruby's or Rust's implicit
returns (though at least Rust is less magical about it).

------
pbnjay
This clouds up your godoc with unnecessary names though. Why not just
initialize a default value at the top of your function? You don't get the bare
returns but it's a lot cleaner.

~~~
notheguyouthink
Does it? Names are documentation no? Eg, that's the one thing I actually
_like_ about named return values.

In my perfect world, we would have named return values by default, so then we
could use them to document the return values, but never empty returns. Empty
returns are the only problem with named return values Imo, as it's easy to
accidentally slip values into the return that you didn't intend.

Though, I had always wondered about returning copies like Foo{} on every
return.. guess I know now.

 _edit_ : As an aside, I should not dismiss your cluttering comment. I did so,
because I feel it's unrelated to this exact topic. If named return values,
something which by it's very nature conveys additional information, is
cluttering the godocs, then that should be a bug, and filed/fixed accordingly.
Imo.

~~~
pbnjay
This post specifically used very short uninformative names though, which was
more to my point. If you're not going to use informative names, it shouldn't
be part of the signature, especially when its barely any extra typing to do
the same within the function body.

~~~
notheguyouthink
That I can definitely agree with.

------
piinbinary
I don't know all that much about compilers, but I'm slightly surprised that Go
doesn't automatically optimize the first into being the same as the second.

~~~
pcwalton
Generally, any modern optimization pipeline that includes global value
numbering and basic memory dependence analysis will perform that
transformation, yes.

~~~
coldtea
Modern being the operative word here.

------
kazinator
I don't understand, through these examples, why the introduction of a _name_
is necessary in order that an empty return statement be used.

The name doesn't even appear in the function. A name that is declared but not
subsequently mentioned serves no purpose (or some side purpose/hack).

In the "NoNamedReturnValue" variant, the return _type_ is still declared. The
compiler could, from that type alone, infer that "return" means "return a
representative default instance of that type".

That is to say, why can't Go programmers just have this:

    
    
      // oi name removed:
      func NamedReturnParams(i int) (/* oi */ objectInfo) {
    
    	if i == 1 {
    		// Do one thing
    		return // wee, allow this anyway!
    	}
    
    	if i == 2 {
    		// Do another thing
    		return
    	}
    
    	if i == 3 {
    		// Do one more thing still
    		return
    	}
    
    	// Normal return
    	return
      }
    

Also, why can't the compiler just optimize away the "return Objectinfo {}"
statements down to "return", if those really are equivalent.

------
mioelnir
I very, very rarely use named return values. My usual go-to problem is when
one of the return values is an `error` that I want to set inside `recover()`.

~~~
frou_dh
Surprised to find this not mentioned in the article and buried in comments.
It's the first thing that comes to my mind as not merely a benefit, but an
essential role played by the named returns.

------
19eightyfour
I was going to post "But JS has this:

    
    
        return { named_var_1, named_var_2 }
    
        const { named_var_1, named_var_2 } = f()
    

But then I read the article.

I don't know really what is going on in this article on a quick reading, but
it builds by existing sense that go is a really cool language that I ought to
get into.

I have no idea if anyone wants to help me understand, but in the last part
where he changes to use a named return parameter, he says, you may also "enjoy
the cleaner look of the source code, too". To me the only difference I see is
the return name, to the right of the existing function signature. What was I
missing that makes this actually cleaner?

~~~
alexhornbake
Naming the return value in the function signature will both allocate the named
variable, as well as make it the default variable to return.

Returning a new unnamed variable for every return will cause all of the
unnamed variables to be allocated.

It's interesting, I don't use this feature of the language... my default way
to write this would have been:

    
    
      func NoNamedReturnParams(i int) (*objectInfo) {
            obj := &objectInfo{}
    	if i == 1 {
    		// Do one thing
    		return obj
    	}
    
    	if i == 2 {
    		// Do another thing
    		return obj
    	}
    
    	if i == 3 {
    		// Do one more thing still
    		return obj
    	}
    
    	// Normal return
    	return obj
      }

~~~
19eightyfour
I had a bit of a play around with it. It's pretty powerful being able to see
<func name> <params type> <return type> in one line ( or possibly multi line )

It really hammers home the concept that a function is a transformation, and of
what into what. And I think this syntax would probably encourage pure
functions. And it's so useful to allocate the return in the top line. I really
like go.

~~~
ryeguy
What language that has static types _doesn 't_ have the func, params, and
return type in one line?

~~~
masklinn
Some HM language can infer types at the toplevel so you may not have an
explicit signature at all, although that's generally frowned upon:

    
    
        add1 = map (+1)
    

OTOH they also split the signature and function "header" so that you don't
need to remove the "noise" to get the bare signature e.g.

    
    
        add1 :: (Num a) => [a] -> [a]
        add1 = map (+1)

------
asdfaoeu
Sounds like an explicit version of
[https://en.wikipedia.org/wiki/Return_value_optimization](https://en.wikipedia.org/wiki/Return_value_optimization)
.

~~~
dom0
No, RVO is about the compiler silently moving the on-stack location of the
"returned" object _into the callers frame_.

------
azinman2
This is a neat trick. But when I look at their examples it seems more like err
conditions rather than normal behavior for the early return, in which case
they should add the error into the return tuple?

------
donatj
For me, the biggest reason I use named parameters is when something I'm
’defer’ring can fail. You can set your err return value within your defer only
if it's named.

I went into reading this expecting that use case but was saddened it was not
mentioned. The use case the author does give is kind of meh, I find it to be
harder to understand what is going on than returning as usual, and that's
worse than the slight supposed compiler gain is worth.

~~~
lobster_johnson
This is really a Go wart, in my opinion. Go _forces_ you into this pattern,
because there's no other way if you want to use defers. So while it's true
that it's a legit use of named return values, it's an unfortunate one, too.

~~~
donatj
I feel like a lot of deferred errors go unhandled because inexperienced devs
don't know that they can.

~~~
dullgiulio
That's one big reason why naked returns are frowned upon.

It's much easier to read code where there is a clean "return nil,
fmt.Errorf(...)".

------
zaphar
This isn't necessarily an argument for named return values. It's an argument
for declaring your return value up front and even then it's really just an
argument for Go to do a better job in the compiler here.

Named return values are one way to declare your return value up front but you
could just as easily have had a oi := objectInfo{} line at the top of your
function too with the same effect.

------
andreasgonewild
I feel like it was a mistake to allow mixing the two styles inside the same
function. I ran into enough issues with non-initialized returns during my
adventures in Go to stop using named return parameters completely. To me, this
feature has the same appeal as JavaScript's optional semicolons; or Pascals
with-statements; convenience at the price of reliability and correctness.

------
pklausler
Leaving aside any quick benefits in code size or run time, named return values
might make code more readable.

Fortran functions have always (since Fortran II anyway) used named result
values; so did Pascal. Since you can now pick the name of the result value
variable in Fortran, I find it a useful convention to just always put
RESULT(RESULT) on my functions.

------
camgunz
I went this route a little for a side project because it's natural to pass up
errors via `err` this way, but I found out you have to have a naked return at
the end of your function no matter what. I can't at all think of a reason for
this; is there one?

------
y4m4b4
[https://github.com/golang/go/issues/20859#issuecomment-31220...](https://github.com/golang/go/issues/20859#issuecomment-312208678)

------
pfarnsworth
I actually hate named return values. I'm relatively new to Go, but I like some
of the ideas about it. Named return values is something about Go that I
despise because it is absolutely misused in my opinion. For such an
opinionated language, with some opinions that I don't agree with, this is one
that I vehemently disagree with.

It makes the code a lot harder to read, and you need to keep more memorized
"magic" in your head. For example, you can't just look at the return values to
figure out what a function returns, now you need to look to see if the return
values are named, and then trace through that.

I very much prefer explicit code as opposed to implicit code, especially on a
day-to-day basis. It just makes my life a lot easier in the long run.

~~~
nickcw
I think you are talking about bare returns, which are somewhat orthogonal to
named return values.

You can use non-bare returns with named return values, just mention the names
in the return statement. This compiles to the same code as the bare return.

I'm a bit ambivalent about bare returns, but named return values are useful,
especially in the presence of defer statements.

------
hota_mazi
I'm not familiar with Go and I'm confused by the fact that even though the
returned variable is named, e.g. "ch", that name is never mentioned in the
function body.

What am I missing?

~~~
dullgiulio
Naked returns. Basically, you just write "return" and that returns the values
declared as named return parameters.

If they are never mentioned in the body you probably have a return of the
default nil value for the named return variables.

But then at least one return is not naked and returns some value, discarding
the named one.

I think it's a bad use of named returns.

------
optimuspaul
These don't represent a real world application at all. I'm not convinced this
is anything more than a compiler optimization for a function that is
essentially a noop.

------
patrickxb
Or you could return a pointer...

------
voidlogic
>In fact we are also investigating if we can develop a little utility to help
or automate this process.

go fix?

Also, it seems like this is begging for a compiler optimization that will make
this all obsolete...

------
jlebrech
this helps with legibility I think, you can see by the function definition
that you have return variables: a,b,c and don't have to scan all the returns
to see which order things are in.

