This question already has an answer here:
Why I get 0 and 1 in the following golang code example with defer
(1 answer)
Closed 11 months ago.
I've been staring at this code and can't figure out the why of its behavior.
package main
import (
"fmt"
)
var i int
func example() int {
defer func() {
fmt.Println("defer")
i = 1
}()
fmt.Println("first")
return i
}
func main() {
fmt.Println(example())
fmt.Println(i)
}
At first, the expected output for me is:
first
defer
1
1
But, as you can see in the playground the actual output is:
first
defer
0
1
Is it a deferred anonymous function behavior? Nope
So, why is it printing 0?
Does defer runs after function returns?
Certainly.
So, why is it printing 0?
Because you're returning 0.
example() returns an int by value. when return i is evaluated, is current value is returned. After that return is evaluated, the defer function executes, changing the value stored at i to 1. But the 0 value is already the return value.
Go makes it possible to modify the return value of a function, but only if the return value has a name.
For example, this returns 1:
func example() (j int) {
defer func() { j = 1 }()
return 0
}
But in your case, you're not naming your return variable, so you can't modify it in a defer.
Related
Hi I want to write a generic function to trace error message when a function returns error. So I wrote this:
func TraceError1(err *error) {
if err != nil && *err != nil {
pc := make([]uintptr, 15)
n := runtime.Callers(2, pc)
frames := runtime.CallersFrames(pc[:n])
frame, _ := frames.Next()
fmt.Printf("%s:%d %s\n", frame.File, frame.Line, frame.Function)
}
}
func TraceError2(err error) {
if err != nil {
pc := make([]uintptr, 15)
n := runtime.Callers(2, pc)
frames := runtime.CallersFrames(pc[:n])
frame, _ := frames.Next()
fmt.Printf("%s:%d %s\n", frame.File, frame.Line, frame.Function)
}
}
func foo() (err error) {
defer TraceError1(&err)
defer TraceError2(err)
fmt.Println("do something")
return fmt.Errorf("haha")
}
TraceError1 works but TraceError2 didn't. In my understanding, error is an interface so it is a pointer/address, why do I need to pass its address? Why TraceError2 cannot work? Thanks.
In case of TraceError1 you are passing a pointer to the named return value err. The pointer is non-nil, but the value it points at (err) is nil (at the time of defer). However, it is not yet evaluated (dereferenced) because TraceError1 has not yet been called. By the time the function does run (after foo returns) and the pointer gets dereferenced, the value of err has been updated (by the return statement inside foo).
However, in case of TraceError2, a nil interface value is passed, which will stay nil even when TraceError2 executes eventually.
Here is a simpler example:
package main
import "fmt"
func intByValue(i int) {
fmt.Printf("i = %d\n", i)
// ^--- `i` is an integer value
// --- whatever i was passed to the function, gets printed
}
func intByRef(i *int) {
var v int = *i // i is a pointer to an int, which gets dereferenced here
// the *address* where the actual value resides was passed
// while the address stays the same, its value can change before
// i is dereferenced, and its value stored in v.
fmt.Printf("i = %d\n", v)
}
func main() {
var i int
defer intByValue(i) // passed the *value* of i, which is 0 right now
defer intByRef(&i) // passed a *pointer* to i, which contains 0 right now
i = 100 // before intByRef could "dereference" its argument, the value that it
// contained has been updated
// intByRef gets called, dereferences the value, finds 100, prints it.
// intByValue gets called, finds 0, prints it
// result should be:
// i = 100
// i = 0
}
So unfortunately, if you want the ability to update the error (e.g. by returning a named return value) before it gets used by the deferred function, you are going to have to pass around pointers to the variable.
In other words, TraceError2 is simply not suited for your use case.
Edit: use correct terminology and (questionably) improve example code.
As go blog explained
The behavior of defer statements is straightforward and predictable.
There are three simple rules:
A deferred function's arguments are evaluated when the defer statement is evaluated.
Deferred function calls are executed in Last In First Out order after the surrounding function returns.
Deferred functions may read and assign to the returning function's named return values.
According to first point, when you call defer TraceError2(err) , that err = nil and that is the value pass to the TraceError2 function.
TraceError1(err *error) works because it is getting a pointer to err, and that pointer value is assigned before defer func TraceError1 is executed.
Simple example code to explain the behaviour.
package main
import (
"fmt"
"runtime"
)
func main() {
i := 0
defer func(i int) {
fmt.Printf("%d\n",i) //Output: 0
}(i)
defer func(i *int) {
defer fmt.Printf("%d\n",*i) //Output: 1
}(&i)
i++
}
In chapter 8 of The Go Programming Language, there is a description to the concurrency echo server as below:
The arguments to the function started by go are evaluated when the go statement itself is executed; thus input.Text() is evaluated in the main goroutine.
I don't understand this. Why the input.Text() is evaluated at the main goroutine? Shouldn't it be in the go echo() goroutine?
// Copyright © 2016 Alan A. A. Donovan & Brian W. Kernighan.
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
// See page 224.
// Reverb2 is a TCP server that simulates an echo.
package main
import (
"bufio"
"fmt"
"log"
"net"
"strings"
"time"
)
func echo(c net.Conn, shout string, delay time.Duration) {
fmt.Fprintln(c, "\t", strings.ToUpper(shout))
time.Sleep(delay)
fmt.Fprintln(c, "\t", shout)
time.Sleep(delay)
fmt.Fprintln(c, "\t", strings.ToLower(shout))
}
//!+
func handleConn(c net.Conn) {
input := bufio.NewScanner(c)
for input.Scan() {
go echo(c, input.Text(), 1*time.Second)
}
// NOTE: ignoring potential errors from input.Err()
c.Close()
}
//!-
func main() {
l, err := net.Listen("tcp", "localhost:8000")
if err != nil {
log.Fatal(err)
}
for {
conn, err := l.Accept()
if err != nil {
log.Print(err) // e.g., connection aborted
continue
}
go handleConn(conn)
}
}
code is here: https://github.com/adonovan/gopl.io/blob/master/ch8/reverb2/reverb.go
How go keyword works in Go, see
Go_statements:
The function value and parameters are evaluated as usual in the calling goroutine, but unlike with a regular call, program execution does not wait for the invoked function to complete. Instead, the function begins executing independently in a new goroutine. When the function terminates, its goroutine also terminates. If the function has any return values, they are discarded when the function completes.
The function value and parameters are evaluated in place with the go keyword (same for the defer keyword see an example for defer keyword).
To understand the evaluation order, let's try this:
go have()(fun("with Go."))
Let's run this and read the code comments for the evaluation order:
package main
import (
"fmt"
"sync"
)
func main() {
go have()(fun("with Go."))
fmt.Print("some ") // evaluation order: ~ 3
wg.Wait()
}
func have() func(string) {
fmt.Print("Go ") // evaluation order: 1
return funWithGo
}
func fun(msg string) string {
fmt.Print("have ") // evaluation order: 2
return msg
}
func funWithGo(msg string) {
fmt.Println("fun", msg) // evaluation order: 4
wg.Done()
}
func init() {
wg.Add(1)
}
var wg sync.WaitGroup
Output:
Go have some fun with Go.
Explanation go have()(fun("with Go.")):
First in place evaluation takes place here:
go have()(...) first have() part runs and the result is fmt.Print("Go ") and return funWithGo, then fun("with Go.") runs, and the result is fmt.Print("have ") and return "with Go."; now we have go funWithGo("with Go.").
So the final goroutine call is go funWithGo("with Go.")
This is a call to start a new goroutine so really we don't know when it will run. So there is a chance for the next line to run: fmt.Print("some "), then we wait here wg.Wait(). Now the goroutine runs this funWithGo("with Go.") and the result is fmt.Println("fun", "with Go.") then wg.Done(); that is all.
Let's rewrite the above code, just replace named functions with anonymous one, so this code is same as above:
For example see:
func have() func(string) {
fmt.Print("Go ") // evaluation order: 1
return funWithGo
}
And cut this code select the have part in the go have() and paste then select the have part in func have() and press Delete on the keyboard, then you'll have this:
This is even more beautiful, with the same result, just replace all functions with anonymous functions:
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
wg.Add(1)
go func() func(string) {
fmt.Print("Go ") // evaluation order: 1
return func(msg string) {
fmt.Println("fun", msg) // evaluation order: 4
wg.Done()
}
}()(func(msg string) string {
fmt.Print("have ") // evaluation order: 2
return msg
}("with Go."))
fmt.Print("some ") // evaluation order: ~ 3
wg.Wait()
}
Let me explain it with a simple example:
1. Consider this simple code:
i := 1
go fmt.Println(i) // 1
This is clear enough: the output is 1.
But if the Go designers decided to evaluate the function argument at the function run-time nobody knows the value of i; you might change the i in your code (see the next example)
Now let's do this closure:
i := 1
go func() {
time.Sleep(1 * time.Second)
fmt.Println(i) // ?
}()
The output is really unknown, and if the main goroutine exits sooner, it even won't have a chance to run: Wake up and print the i, which is i itself may change to that specific moment.
Now let's solve it like so:
i := 1
go func(i int) {
fmt.Printf("Step 3 i is: %d\n", i) // i = 1
}(i)
This anonymous function argument is of type int and it is a value type, and the value of i is known, and the compiler-generated code pushes the value 1 (i) to the stack, so this function, will use the value 1, when the time comes (A time in the future).
All (The Go Playground):
package main
import (
"fmt"
"sync"
"time"
)
func main() {
i := 1
go fmt.Println(i) // 1 (when = unknown)
go fmt.Println(2) // 2 (when = unknown)
go func() { // closure
time.Sleep(1 * time.Second)
fmt.Println(" This won't have a chance to run", i) // i = unknown (when = unknown)
}()
i = 3
wg := new(sync.WaitGroup)
wg.Add(1)
go func(i int) {
defer wg.Done()
fmt.Printf("Step 3 i is: %d\n", i) // i = 3 (when = unknown)
}(i)
i = 4
go func(step int) { // closure
fmt.Println(step, i) // i=? (when = unknown)
}(5)
i = 5
fmt.Println(i) // i=5
wg.Wait()
}
Output:
5
5 5
2
1
Step 3 i is: 3
The Go Playground output:
5
5 5
1
2
Step 3 i is: 3
As you may be noticed, the order of 1 and 2 is random, and your output may differ (See the code comments).
I am reading through the go specification and don't fully understand the behavior of an example for defer.
// f returns 1
func f() (result int) {
defer func() {
result++
}()
return 0
}
The function has a named return, which an anonymous deferred function increments. The function ends with "return 0". This value is not returned, but the incremented variable instead.
In trying to understand this behavior, I've run into more questions. If I assign a value to the return variable, that seems to have no effect on the return value.
//b returns 1
func b() (result int) {
result = 10
defer func() {
result++
}()
return 0
}
However, if the last line is changed to:
return result
Things behave as I would expect.
https://play.golang.org/p/732GZ-cHPqU
Can someone help me better understand why these values get returned and the scope of these functions.
The specification says this about deferred functions:
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.
and and this about return statements:
A "return" statement that specifies results sets the result parameters before any deferred functions are executed.
Example 1:
func f() (result int) {
defer func() {
result++
}()
return 0
}
The result variable is initialized to zero; the return statement sets result to zero; the deferred function increments result to 1; the function returns 1.
Example 2:
func b() (result int) {
result = 10
defer func() {
result++
}()
return 0
}
The result variable is set to 10 in the first statement of the function; the return statement sets result to zero; the deferred function increments result to 1; the function returns 1.
Example 3:
func c() (result int) {
result = 10
defer func() {
result++
}()
return result
}
The result variable is set to 10 in the first statement of the function; the return statement sets result to 10; the deferred function increments result to 11, the function returns 11.
Can anyone explain why 0's and 1's are printed and not anything else? Thank you!
func makeFunction(name string) func() {
fmt.Println("00000")
return func() {
makeFunction2("abcef")
}
}
func makeFunction2(name string) func() {
fmt.Println("11111")
return func() {
makeFunction3("safsf")
}
}
func makeFunction3(name string) func() {
fmt.Println("33333")
return func() {
fmt.Printf("444444")
}
}
func main() {
f := makeFunction("hellooo")
f()
}
Can anyone explain why 0's and 1's are printed and not anything else? Thank you!
Let's follow the program flow:
main starts.
main calls makeFunction.
makeFunction prints 00000, and returns an anonymous function.
Back in main, we call the anonymous function returned by the previous call.
The anonymous function calls makeFunction2.
makeFunction2 prints 11111, and returns an anonymous function.
main returns.
Because the return value is discarded after step 6 above, nothing else is printed.
Let's look at your main:
Line 1
f := makeFunction("hellooo")
Side effect: printing "00000"
Return value: an anonymous function that executes makeFunction2("abcef"), assigned to the identifier f
Line 2
f()
which is equivalent to:
_ = f()
Side effect: printing "11111"
Return value: an anonymous function that executes makeFunction3("safsf"), discarded (you are not assigning the return value of f()).
makeFunction3 is never assigned to any identifier, and never called.
To prints the 3's, you have to call twice:
f()()
And to prints the 4's too, just do:
f()()()
Because ...
// prints "00000" and returns a function that if run
// will invoked `makeFunction2`
f := makeFunction("hello")
// `makeFunction2` is called, printing "11111" and returns
// a function that if run will invoked `makeFunction3`
f1 := f()
// `makeFunction3` is called, printing "33333" and returns
// a function that if run will invoked `makeFunction4`
f2 := f1()
Test question, what does it print out if you do this?
f := makeFunction("Hello")()()
f()
This is known as currying or closure, but in your example you have not closed over any local value so the latter loses its meaning.
makeFunction only return the function makeFunction2. since this is not a recursive function. If you expecting to behave like recursive function, then you should change return func(){} to (return makeFunction2 or 3)
func makeFunction(name string) func() {
fmt.Println("00000")
return makeFunction2("abcef")
}
func makeFunction2(name string) func() {
fmt.Println("11111")
return makeFunction3("safsf")
}
func makeFunction3(name string) func() {
fmt.Println("33333")
return func() {
fmt.Printf("444444")
}
}
func main() {
f := makeFunction("hellooo")
f()
}
// Output:
00000
11111
33333
444444
The Reason is it only returns the anonymous funtions.
package main
import "fmt"
func makeFunction(name string) func() {
fmt.Println("00000")
return func(){
makeFunction2("abcef")()
}
}
func makeFunction2(name string) func() {
fmt.Println("11111")
return func() {
makeFunction3("safsf")()
}
}
func makeFunction3(name string) func() {
fmt.Println("33333")
return func() {
fmt.Printf("444444")
}
}
func main() {
f := makeFunction("hellooo")
f()
}
I just started learning Go and I got confused with one example about using defer to change named return value in the The Go Blog - Defer, Panic, and Recover.
The example says:
Deferred functions may read and assign to the returning function's named return values.
In this example, a deferred function increments the return value i after the surrounding function returns. Thus, this function returns 2:
func c() (i int) {
defer func() { i++ }()
return 1
}
But as what I have learned from A Tour of Go - Named return values
A return statement without arguments returns the named return values. This is known as a "naked" return.
I tested in the following code and in function b it returns 1 because it wasn't the "A return statement without arguments" case mentioned above.
func a() (i int) { // return 2
i = 2
return
}
func b() (i int) { // return 1
i = 2
return 1
}
So my question is in the first example, the surrounding function c has a named return value i, but the function c uses return 1 which in the second example we can see it should have return 1 no matter what value i is. But why after i changes in the deferred function the c function returns the value of i instead the value 1?
As I was typing my question, I might have guessed the answer. Is it because:
return 1
is equals to:
i = 1
return
in a function with a named return value variable i?
Please help me confirm, thanks!
A defer statement pushes a function call onto a list. The list of saved calls is executed after the surrounding function returns. -- The Go Blog: Defer, Panic, and Recover
Another way to understand the above statement:
A defer statements pushes a function call onto a stack. The stack of saved calls popped out (LIFO) and deferred functions are invoked immediately before the surrounding function returns.
func c() (i int) {
defer func() { i++ }()
return 1
}
After 1 is returned, the defer func() { i++ }() gets executed. Hence, in order of executions:
i = 1 (return 1)
i++ (defer func pop out from stack and executed)
i == 2 (final result of named variable i)
For understanding sake:
func c() (i int) {
defer func() { fmt.Println("third") }()
defer func() { fmt.Println("second") }()
defer func() { fmt.Println("first") }()
return 1
}
Order of executions:
i = 1 (return 1)
"first"
"second"
"third"
According to the Go Specification:
Return Statements
A "return" statement that specifies results sets the result parameters before any deferred functions are executed.
Defer Statements
"...deferred functions are invoked immediately before the surrounding function returns..."
So yes, as you assumed, the named return variable is assigned, then the deferred statement increments it.
I would add that named return parameters can lead to subtle bugs, and generally should be avoided unless there's no alternative.
I think the confusion is about function in function how about if you classified like this:
func main() {
fmt.Println(c()) //the result is 5
}
// the c function returned value is named j
func c() (j int) {
defer changei(&j)
return 6
}
func changei(j *int) {
//now j is 6 because it was assigned by return statement
// and if i change guess what?! i changed the returned value
*j--;
}
but if the return value is not named like this:
func main() {
fmt.Println(c()) //the result will become 6
}
// the c function returned value is not named at this time
func c() int {
j := 1
defer changei(&j)
return 6
}
func changei(j *int) {
//now j = 1
// and if i change guess what?! it will not effects the returned value
*j--;
}
I hope this will clear the confusion and that is how i did happy Go coding