Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Iterating slice of values and calling their method with pointer receiver behaves inconsistently #28844

Closed
Kefaise opened this issue Nov 17, 2018 · 2 comments

Comments

@Kefaise
Copy link

Kefaise commented Nov 17, 2018

What version of Go are you using (go version)?

$ go version
go version go1.11.2 windows/amd64

Does this issue reproduce with the latest release?

Yes

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
set GOARCH=amd64
set GOBIN=
set GOCACHE=C:\Users\kefaise\AppData\Local\go-build
set GOEXE=.exe
set GOFLAGS=
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOOS=windows
set GOPATH=C:\Users\kefaise\go
set GOPROXY=
set GORACE=
set GOROOT=C:\Go
set GOTMPDIR=
set GOTOOLDIR=C:\Go\pkg\tool\windows_amd64
set GCCGO=gccgo
set CC=gcc
set CXX=g++
set CGO_ENABLED=1
set GOMOD=
set CGO_CFLAGS=-g -O2
set CGO_CPPFLAGS=
set CGO_CXXFLAGS=-g -O2
set CGO_FFLAGS=-g -O2
set CGO_LDFLAGS=-g -O2
set PKG_CONFIG=pkg-config
set GOGCCFLAGS=-m64 -mthreads -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=C:\Users\kefaise\AppData\Local\Temp\go-build992843230=/tmp/go-build -gno-record-gcc-switches

What did you do?

I tried to call method which use goroutine on all elements of slice. It didn't work, so I tried four different variations:

  1. Slice of values, receiver is by pointer
  2. Slice of values, receiver is by value
  3. Slice of pointers, receiver is by pointer
  4. Slice of pointers, receiver is by value

Only slice of values, receiver is by pointer behave inconsistently. I am aware that calling goroutine inside loop requires copy of variables one will use inside it. However this may cause hard to find bugs when one change method to use pointer receiver, or start using goroutines inside method. Moreover goroutine is called in context of method, so one might expect that receiver is stable in closure, when he don't change it.

Program to reproduce this behaviour:
https://play.golang.org/p/DK0IdNnZMk5

What did you expect to see?

Something similar to

Pointer
foo0
foo6
foo2
foo3
foo4
foo5
foo9
foo1
foo7
foo8

bar1
bar2
bar4
bar5
bar0
bar3
bar6
bar7
bar9
bar8

Value
foo0
foo6
foo2
foo3
foo4
foo5
foo9
foo1
foo7
foo8

bar0
bar1
bar2
bar3
bar4
bar5
bar6
bar9
bar8
bar7

What did you see instead?

Pointer
foo4
foo4
foo8
foo8
foo8
foo8
foo8
foo9
foo9
foo9

bar1
bar2
bar4
bar5
bar0
bar3
bar6
bar7
bar9
bar8

Value
foo0
foo6
foo2
foo3
foo4
foo5
foo9
foo1
foo7
foo8

bar0
bar1
bar2
bar3
bar4
bar5
bar6
bar9
bar8
bar7
@AlexRouSg
Copy link
Contributor

This is not a bug.

for _, txtValue := range textsValues {
	txtValue.printPointer(&wg)
}

Is equivalent to

var txtValue textHandler
for i := 0; i < len(textsValues); i++ {
        txtValue = textsValues[i]
	txtValue.printPointer(&wg)
}

When you take the pointer of txtValue , for the entire loop, it will be the same variable. Thus by the time the goroutine printed the value, it changed to something else as it's further along the loop.

@mvdan
Copy link
Member

mvdan commented Nov 17, 2018

What @AlexRouSg said. There are plenty of articles on this subject online - for example, see https://github.com/golang/go/wiki/CommonMistakes#using-goroutines-on-loop-iterator-variables.

@mvdan mvdan closed this as completed Nov 17, 2018
@golang golang locked and limited conversation to collaborators Nov 17, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants