return value in function when using defer - go

I have some problem with using 'defer' about the return value. I tried to run one test function in different way (only the definition of i is different), but the result is different. So, I'm confused about the different return value. Here is the problem:
function 1:
package main
import "fmt"
func main() {
fmt.Println("a return:", a()) // return value: 0
}
func a() int {
var i int
defer func() {
i++
fmt.Println("a defer1:", i) // print " a defer1: 1"
}()
return i
}
return value:
a defer1: 1
a return: 0
function 2:
package main
import "fmt"
func main() {
fmt.Println("a return:", a()) // return value: 1
}
func a() (i int) {
defer func() {
i++
fmt.Println("a defer1:", i) // print " a defer1: 1"
}()
return i
}
return value:
a defer1: 1
a return: 1
One of the return values is 0, the other is 1. So, the question is what's the difference between the two function.

what's the difference between the two functions?
The Go Programming Language Specification
Defer statements
A "defer" statement invokes a function whose execution is deferred to
the moment the surrounding function returns.
Each time a "defer" statement executes, the function value and
parameters to the call are evaluated as usual and saved anew but the
actual function is not invoked. Instead, deferred functions are
invoked immediately before the surrounding function returns, in the
reverse order they were deferred.
if the deferred function is a function literal and the surrounding
function has named result parameters that are in scope within the
literal, the deferred function may access and modify the result
parameters before they are returned. If the deferred function has any
return values, they are discarded when the function completes.
The difference is a surrounding function with a named result parameter
func a() (i int)
versus a surrounding function with an unnamed result parameter
func a() int

Related

Why I get 0 and 1 in the following golang code example with defer

Call to defer produces different results for variables declared in two different ways
package main
import (
"fmt"
)
func c(i int) int {
defer func() { i++ }()
return i
}
func c1() (i int) {
defer func() { i++ }()
return i
}
func c2() (i int) {
defer func() { i++ }()
return 2
}
func main() {
fmt.Println(c(0)) // Prints 0
fmt.Println(c1()) // Prints 1
fmt.Println(c2()) // Prints 3 Thank you icza
}
https://play.golang.org/p/gfnnCZ--DkH
In the first example i is an (incoming) parameter. At the return statement the return value is evaluated, and the deferred function runs after this, and incrementing i in that has no effect on the return value.
In the second example i is the name of the result parameter. At the return statement you explicitly return the value i, which is then assigned to the return value i (this is a no-op). But deferred functions are allowed to modify the values of the return "variables", and if they do so, that will have an effect on the actual returned values.
This becomes clearer if we add another example:
func c2() (i int) {
defer func() { i++ }()
return 2
}
This function will return 3, because the return 2 statement will assign 2 to i, then the deferred function will increment this, and so the return value will be 3. Try this one on the Go Playground. Relevant part from the Spec: Return statements:
A "return" statement that specifies results sets the result parameters before any deferred functions are executed.
In general, if a function (or method) has named result parameters, the return values will always be the values of those variables, but must not forget that a return statement may assign new values to these result paramteters, and they may be modified by deferred functions after a return statement.
This is mentioned in the Spec: Defer statements:
For instance, if the deferred function is a function literal and the surrounding function has named result parameters that are in scope within the literal, the deferred function may access and modify the result parameters before they are returned.
It is also mentioned in the blog post Defer, Panic and Recover:
Deferred functions may read and assign to the returning function's named return values.
And also in Effective Go: Recover:
If doParse panics, the recovery block will set the return value to nil—deferred functions can modify named return values.
See related question: How to return a value in a Go function that panics?

Can you get a data race when deferring a mutex unlock in go?

Is this Get method buggy and prone to a theoretical data race?
type item struct {
val int
mutex sync.RWMutex
}
func (i *item) Set(val int) {
i.mutex.Lock()
defer i.mutex.Unlock()
i.val = val
}
func (i *item) Get() int {
i.mutex.RLock()
defer i.mutex.RUnlock()
return i.val
}
I ask because I saw a rare data race when running my tests with -race with the former code, but can't find any way of duplicating the effect.
Is it possible for i.val to be set to a different value between when the defer carries out the RUnlock, and when we read and return the value from the struct?
Must Get() be something like this instead?:
func (i *item) Get() int {
i.mutex.RLock()
defer i.mutex.RUnlock()
val := i.val
return val
}
Your code is safe, deferred functions are executed after the expression list of the return statement is evaluated. If you would have named result parameters, the return values would also be assigned to them before calling the deferred functions (and you could even modify the return values before "truly" returning from the enclosing function).
No need to create a local variable to store i.val.

What is the difference between named return value and normal return value?

My question is about the different named return value vs normal return value.
my code
package main
import "fmt"
func main() {
f := fmt.Println
f(a())
f(b())
}
func a() int {
i := 0
defer func() {
i += 1
fmt.Println("a defer : ", i)
}()
return i
}
func b() (i int) {
i = 0
defer func() {
i += 1
fmt.Println("b defer : ", i)
}()
return i
}
the result:
the a function return 0
the b function reutrn 1
Why?
The named return value also allocates a variable for the scope of your function.
func a() int: While you already return the value of i = 0, but since no named values was defined the static value got returned. So even though you're increasing i in the deferred function it doesn't affect the returned value.
func b() (i int): The variable i is allocated (and already initialized to 0). Even though the deferred function runs after the i = 0 was returned the scope is still accessible and thus still can be changed.
Another point of view: you can still change named return values in deferred functions, but cannot change regular return values.
This especially holds true in the following example:
func c() (i int) {
defer func() {
i = 1
fmt.Println("c defer : ", i)
}()
return 0
}
defer runs a function after the return statement but before the function is auctually returned, thus enabling modify returned results. However, only named return results can be accessed normally, i.e. by the variable name.
The return statement, when not naked (another thing about named return, but irrelevant here), the expression got evaluated. And if the return is named, the named variable is assigned with the evaluated value.
In your code, in func a() int the return is typed but not named. So when return i is execuated, it sets the return value, a variable not available to the code, as the value of i. You can consider it as RETVAL := i. And later, your deferred function modified i but the return value (RETVAL) remains unchanged.
But in func b() (i int), i is a named return. Thus, when return i execuate, it literally translate to i = i. And later, your deffered function modified i, a return value, so the returned value change.
More on return: https://golang.org/ref/spec#Return_statements
With the named return value you directly modify what gets returned, with the "normal" return value you just modify local variable in the scope of your function, which never gets returned.
More on this:
Deferred function can access named return values but it has no return value itself - so this is actually the only way to modify main function results from there. Very useful thing.
Imagine you want to fix code which panics - you want it to return the error instead. You can solve it by using recover in a deferred function and then assigning recovered error to named return value.
Example, somewhat abstract but hopefully useful:
func noMorePanics() (err error) {
defer func() {
if r := recover(); r != nil {
err = r.(error)
}
}()
potentiallyPanickingFunction()
}

Go closure variable scope

I'm reading 'CreateSpace An Introduction to Programming in Go 2012'
and on page 86 I found this evil magic
func makeEvenGenerator() func() uint {
i := uint(0)
return func() (ret uint) {
ret = i
i += 2
return
}
}
// here's how it's called
nextEven := makeEvenGenerator()
fmt.Println(nextEven())
fmt.Println(nextEven())
fmt.Println(nextEven())
1) Why is i not resetting ?
2) is nextEven() returning and uint or is Println so smart that it can work with everything ?
For the sake of clarity, I'll assign names to both functions:
func makeEvenGenerator() func() uint { // call this "the factory"
i := uint(0)
return func() (ret uint) { // call this "the closure"
ret = i
i += 2
return
}
}
The factory returns the closure – functions are first class citizens in Go i.e. they can be right-hand expressions, for example:
f := func() { fmt.Println("f was called"); }
f() // prints "f was called"
In your code, the closure wraps over the context of the factory, this is called lexical scoping. This is why the variable i is available inside the closure, not as a copy but as a reference to i itself.
The closure uses a named return value called ret. What this means is that inside the closure you'll have implicitly declared ret and at the point of return, whatever value ret has will be returned.
This line:
ret = i
will assign the current value of i to ret. It will not change i. However, this line:
i += 2
will change the value of i for the next time the closure is called.
Here you'll find a little closure example I wrote together for you. It's not extremely useful but illustrates the scope, purpose and use of closures pretty well in my opinion:
package main
import "fmt"
func makeIterator(s []string) func() func() string {
i := 0
return func() func() string {
if i == len(s) {
return nil
}
j := i
i++
return func() string {
return s[j]
}
}
}
func main() {
i := makeIterator([]string{"hello", "world", "this", "is", "dog"})
for c := i(); c != nil; c = i() {
fmt.Println(c())
}
}
1) Why is i not resetting ?
Closures in Go capture variables by reference. That means the inner function holds a reference to the i variable in the outer scope, and each call of it accesses this same variable.
2) is nextEven() returning and uint or is Println so smart that it can
work with everything ?
fmt.Println() (along with fmt.Print(), fmt.Fprint(), etc.) can work most types. It prints its arguments in the "default format". It is the same thing that is printed using fmt.Printf() using the %v verb.
The variable in closure is free from neither code segment nor context.

Why would return parameters be named?

What benefits arise from naming a function's return parameter(s)?
func namedReturn(i int) (ret int) {
ret = i
i += 2
return
}
func anonReturn(i int) int {
ret := i
i += 2
return ret
}
There are some benefits to naming them:
It serves as documentation.
They are auto-declared and initialized to the zero values.
If you have multiple return sites, you don't need to change them all if you change the function's return values since it will just say "return".
There are also downsides, mainly that it's easy to accidentally shadow them by declaring a variable of the same name.
Effective Go has a section on named result parameters:
The return or result "parameters" of a Go function can be given names
and used as regular variables, just like the incoming parameters. When
named, they are initialized to the zero values for their types when
the function begins; if the function executes a return statement with
no arguments, the current values of the result parameters are used as
the returned values.
The names are not mandatory but they can make code shorter and
clearer: they're documentation. If we name the results of nextInt it
becomes obvious which returned int is which.
func nextInt(b []byte, pos int) (value, nextPos int) {
[...]
Another special use for a named return variable is to be captured by a deferred function literal. A trivial illustration:
package main
import (
"errors"
"fmt"
)
func main() {
fmt.Println(f())
}
var harmlessError = errors.New("you should worry!")
func f() (err error) {
defer func() {
if err == harmlessError {
err = nil
}
}()
return harmlessError
}
Output is <nil>. In more practical scenarios, the deferred function may handle panics, and may modify other return values besides an error result. The magic in common though, is that the deferred literal has a chance to modify the return values of f after f is terminated, either normally or by panic.
It's useful in at least two cases:
Whenever you have to declare variables that you're going to return. E.g.
func someFunc() (int, error) {
var r int
var e error
ok := someOtherFunc(&r) // contrived, I admit
if !ok {
return r, someError()
}
return r, nil
}
vs.
func someFunc() (r int, e error) {
ok := someOtherFunc(&r)
if !ok {
e = someError()
}
return
}
This gets more important as the number of execution paths through the function increases.
When you're documenting return values and want to refer to them by name. godoc considers the return variables part of a function's signature.
For example, named return parameters are accessible by, well, name.
func foo() (a, b, c T) {
// ...
if qux {
b = bar()
}
// ...
return
}
This is not easy to replicate w/o named return parameters. One would have to introduce local variables of essentially the same functionality as named return parameters:
func foo() (T, T, T) {
var a, b, c T
// ...
if qux {
b = bar()
}
// ...
return a, b, c
}
So it's easier to allow that directly.
Additionally, they are accessible also in the other direction:
func foo() (a, b, c T) {
// ...
if a > c {
b = bar()
}
// ...
return
}
Etc.

Resources