how to understand scope in go closure - go

Does anybody know why the case1 output the same result, but the case2 output the sequential result?
I know the reason why case1 output the same value is that the closure of each function in functions slice access to the same scope.
But why after adding i:=i in each loop can case2 output the sequential result?
Does after redefining i in eachloop, a new scope is generated?
like let in javascript?
case1
func main() {
funcs := []func() {}
for i:=0;i<10;i++{
funcs = append(funcs, func() {
fmt.Println(i)
})
}
for i:=0;i<10;i++{
funcs[i]()
}
}
output
10
10
10
10
10
10
10
10
10
10
case2
func main() {
funcs := []func() {}
for i:=0;i<10;i++{
i := i
funcs = append(funcs, func() {
fmt.Println(i)
})
}
for i:=0;i<10;i++{
funcs[i]()
}
}
output
0
1
2
3
4
5
6
7
8
9

This isn't really a scope issue but rather an issue with how the compiler decides if your variable i is captured by reference or by value. This is not always obvious. For loops in go reuse the iteration variable in this case the i. In case1 the variable i is captured as a reference as the compiler sees it as being changed after the capture has taken place. In case2 the inner variable i is created before the capture, captured and released thus the compiler sees it as unchanging and captures it by value. The result is when the functions are run in case1 the results are all the final value as that is what the variable i ended up as and each function only holds a reference to that particular i. In case2 each capture was passed a "copy" of i at the time of creation thus they show the values you expect.

Related

time.Sleep resulting undesired behavior [duplicate]

This question already has an answer here:
goroutines order of execution
(1 answer)
Closed 2 years ago.
import "fmt"
import "time"
func main() {
array := []int{1, 2, 3}
for _, num := range array {
go func() {
fmt.Println(fucknum)
}(fucknum)
time.Sleep(time.Nanosecond)
}
time.Sleep(time.Second)
}
Since there is a time.Sleep within the for-loop, I was expecting the output to be 1 2 3 because of the yielding of execution at each time.Sleep.
However, the output of this piece of code outputs 2 1 3. And after I changed Nanosecond to Microsecond, it turns to be 1 2 3.
For comparison, I also tested python3's asyncio version in which I assume asyncio.call_soon is equivalent to Go's non-IO coroutine.
import asyncio
loop = asyncio.get_event_loop()
async def test():
for i in range(1, 4):
# replace call_soon with asyncio.sleep(0) does not change the result
loop.call_soon(lambda : print(i))
await asyncio.sleep(0)
loop.run_until_complete(test())
And the outputs are always 1 2 3(This output is the same as what I expected as I know that internally, functions scheduled by call_soon is simply added into a FIFO queue)
How to explain the behavior of the Go version?
Because each of the generated goroutines are accessing the same variable defined outside of their scope they are not allocating a new memory address, but are referencing the same address. The for loop in your example actually references the same variable multiple times. By introducing a local scope in the goroutine definition, each time a new goroutine is spawned it will allocate a new variable on each iteration.
To solve the problem you need to pass the index as a parameter for your closure function.
This should fix your problem.
func main() {
array := []int{1, 2, 3}
for _, num := range array {
go func(num int) {
fmt.Println(num)
}(num)
time.Sleep(time.Nanosecond)
}
time.Sleep(time.Second)
}

Calling a variable from another function in go

I know that variables are pass by value in go. However, I want to call a variable that in inside a func outside this function. Let me give you an example:
package main
import (
"fmt"
)
func Smile(){
A := 5
}
func main() {
fmt.Println(A)
}
This gives me undefine A.
what is the best way to pass A ? Should I use a pointer? How do I do that?
It's not possible to print the value of the A variable declared in the Smile() function from main().
And the main reason for that is that the variable A only exists if code execution enters the Smile() function, more precisely reaches the A variable declaration. In your example this never happens.
And even if in some other example this happens (e.g. Smile() is called), an application may have multiple goroutines, and multiple of them may be executing Smile() at the same time, resulting in the app having multiple A variables, independent from each other. In this situation, which would A in main() refer to?
Go is lexically scoped using blocks. This means the variable A declared inside Smile() is only accessible from Smile(), the main() function cannot refer to it. If you need such "sharing", you must define A outside of Smile(). If both Smile() and main() needs to access it, you have to make it either a global variable, or you have to pass it to the functions that need it.
Making it a global variable, this is how it could look like:
var a int
func smile() {
a = 5
fmt.Println("a in smile():", a)
}
func main() {
smile()
fmt.Println("a in main():", a)
}
This outputs (try it on the Go Playground):
a in smile(): 5
a in main(): 5
Declaring it local in main() and passing it to smile(), this is how it could look like:
func smile(a int) {
fmt.Println("a in smile():", a)
}
func main() {
a := 5
fmt.Println("a in main():", a)
smile(a)
}
Output (try it on the Go Playground):
a in main(): 5
a in smile(): 5
The best way is, https://godoc.org/golang.org/x/tools/go/pointer
Pointers
Ex:
func getCar() {
car := Vehicles.Car{}
setModel(&car)
// model ("BMW") will be available here
}
func setModel(car *Vehicles.Car) {
car.Model = "BMW"
}

How to understand this behavior of goroutine?

package main
import (
"fmt"
"time"
)
type field struct {
name string
}
func (p *field) print() {
fmt.Println(p.name)
}
func main() {
data := []field{ {"one"},{"two"},{"three"} }
for _,v := range data {
go v.print()
}
<-time.After(1 * time.Second)
}
why does this code print 3 "three" instead of "one" "two" "three" in any order?
There is a data race.
The code implicitly takes address of variable v when evaluating arguments to the goroutine function. Note that the call v.print() is shorthand for the call (&v).print().
The loop changes the value of variable v.
When goroutines execute, it so happens that v has the last value of the loop. That's not guaranteed. It could execute as you expected.
It's helpful and easy to run programs with the race detector. This data race is detected and reported by the detector.
One fix is to create another variable scoped to the inside of the loop:
for _, v := range data {
v := v // short variable declaration of new variable `v`.
go v.print()
}
With this change, the address of the inner variable v is taken when evaluating the arguments to the goroutine. There is a unique inner variable v for each iteration of the loop.
Yet another way to fix the problem is use a slice of pointers:
data := []*field{ {"one"},{"two"},{"three"} } // note '*'
for _, v := range data {
go v.print()
}
With this change, the individual pointers in the slice are passed to the goroutine, not the address of the range variable v.
Another fix is to use the address of the slice element:
data := []field{ {"one"},{"two"},{"three"} } // note '*'
for i:= range data {
v := &data[i]
go v.print()
}
Because pointer values are typically used with types having a pointer receiver, this subtle issue does not come up often in practice. Because field has a pointer receiver, it would be typical to use []*field instead of []field for the type of data in the question.
If the goroutine function is in an anonymous function, then a common approach for avoiding the issue is to pass the range variables as an argument to the anonymous function:
for _, v := range data {
go func(v field) {
v.print() // take address of argument v, not range variable v.
}(v)
}
Because the code in the question does not already use an anonymous function for the goroutine, the first approach used in this answer is simpler.
As stated above there’s a race condition it’s result depends on delays on different processes and not well defined and predictable.
For example if you add time.Sleep(1*time.Seconds) you likely to get a correct result. Because usually goroutine prints faster than 1second and will have correct variable v but it’s a very bad way.
Golang has a special race detector tool which helps to find such situations. I recommend read about it while reading testing. Definitely it’s worth it.
There’s another way - explicitly pass variable value at goroutine start:
for _, v := range data {
go func(iv field) {
iv.print()
}(v)
}
Here v will be copied to iv (“internal v”) on every iteration and each goroutine will use correct value.

Does a new run of for loop ends the scope of last run of for loop?

I do not understand why following program prints 0 1 2. I thought it will print 2 2 2.
package main
import (
"fmt"
)
func main() {
var funcs []func()
for i := 0; i < 3; i++ {
idx := i
funcs = append(funcs, func() { fmt.Println(idx) })
}
for _, f := range funcs {
f()
}
}
My reasoning of it should print 2 2 2 is that each run of the for loop shared the same scope(e.g., 2nd run of for loop does not terminate the scope of 1st run, the scope are shared). Thus idx's reference is shared by the anonymous function created with in each run of for loop. Thus when the loop ends, all 3 functions created shared the same reference of idx, whose value is 2.
So I think the question boils down to: Does a new run (e.g., i == 2) of for loop ends the scope of last run (e.g., i == 1) of for loop? Would appreciate if answer would point me to golang spec. (I could not find the spec mentioning this).
From spec https://golang.org/ref/spec#For_statements
A "for" statement specifies repeated execution of a block.
each of those blocks has its own scope and they are not nested or shared. But
Each "if", "for", and "switch" statement is considered to be in its
own implicit block.
so variable i in your snippet is shared and
for i := 0; i < 3; i++ {
funcs = append(funcs, func() { fmt.Println(i) })
}
for _, f := range funcs {
f()
}
will print 3 3 3 as expected.

How golang's "defer" capture closure's parameter?

Here is my code (run):
package main
import "fmt"
func main() {
var whatever [5]struct{}
for i := range whatever {
fmt.Println(i)
} // part 1
for i := range whatever {
defer func() { fmt.Println(i) }()
} // part 2
for i := range whatever {
defer func(n int) { fmt.Println(n) }(i)
} // part 3
}
Output:
0
1
2
3
4
4
3
2
1
0
4
4
4
4
4
Question: What's the difference between part 2 & part 3? Why part 2 output "44444" instead of "43210"?
The 'part 2' closure captures the variable 'i'. When the code in the closure (later) executes, the variable 'i' has the value which it had in the last iteration of the range statement, ie. '4'. Hence the
4 4 4 4 4
part of the output.
The 'part 3' doesn't capture any outer variables in its closure. As the specs say:
Each time the "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.
So each of the defered function calls has a different value of the 'n' parameter. It is the value of the 'i' variable in the moment the defer statement was executed. Hence the
4 3 2 1 0
part of the output because:
... deferred calls are executed in LIFO order immediately before the surrounding function returns ...
The key point to note is that the 'f()' in 'defer f()' is not executed when the defer statement executes
but
the expression 'e' in 'defer f(e)' is evaluated when the defer statement executes.
I would like to address another example in order to improve the understanding of defer mechanish, run this snippet as it is first, then switch order of the statements marked as (A) and (B), and see the result to yourself.
package main
import (
"fmt"
)
type Component struct {
val int
}
func (c Component) method() {
fmt.Println(c.val)
}
func main() {
c := Component{}
defer c.method() // statement (A)
c.val = 2 // statement (B)
}
I keep wonderng what are the correct keywords or concepts to apply here. It looks like that the expression c.method is evaluated, thus returning a function binded to the actual state of the component "c" (like taking an snapshot of the component's internal state).
I guess the answer involves not only defer mechanish also how funtions with value or pointer receiver works. Do note that it also happens that if you change the func named method to be a pointer receiver the defer prints c.val as 2, not as 0.

Resources