> 2. A < D < B < C - happens when f2.go is passed first to the compiler. In this case, the *expected output *would be "1 2 1". However, the *actual output* is "1 2 3".
This is not true by my understanding of the spec. https://go.dev/ref/spec#Package_initialization If f2.go is passed first, then the order of uninitialized variables is D < A < B < C. As D depends on A, so D is not initialized in the first initialization cycle. In the first initialization cycle, A, B, and C and initialized as 3, 4, and 3. In the second initialization cycle, D is initialized as 1 and A is changed to 1. So the output should be 1 4 3. The same output is for the case if f1.go is passed first. On Thursday, March 24, 2022 at 5:24:09 AM UTC+8 Ian Lance Taylor wrote: > On Wed, Mar 23, 2022 at 2:01 PM Joao Carlos <joaoper...@gmail.com> wrote: > > > > I'm currently observing a behavior in the package initialization that > looks incompatible with the Go language specification. > > Let's consider the following two .go files which are in the same package > > > > f1.go > > package main > > > > var A int = 3 > > var B int = A + 1 > > var C int = A > > > > f2.go > > package main > > > > import "fmt" > > > > var D = f() > > > > func f() int { > > A = 1 > > return 1 > > } > > > > func main() { > > fmt.Println(A, " ", B, " ", C) > > } > > > > According to the Go language specification, "package-level variable > initialization proceeds stepwise, with each step selecting the variable > earliest in declaration order which has no dependencies on uninitialized > variables". > > > > As such, I would expect two possible orders in which the global > variables can be initialized: > > 1. A < B < C < D - happens when you compile the project by passing f1.go > first to the compiler, followed by f2.go . In this case, the output is "1 4 > 3" > > 2. A < D < B < C - happens when f2.go is passed first to the compiler. > In this case, the expected output would be "1 2 1". However, the actual > output is "1 2 3". > > > > Adding to this, I observed that if we rewrite f1.go to the following, > the program now has the expected behavior when we pass f2.go first to the > compiler. > > > > rewritten f1.go > > package main > > > > import "fmt" > > > > var A int = initA() > > var B int = initB() > > var C int = initC() > > > > func initA() int { > > fmt.Println("Init A") > > return 3 > > } > > > > func initB() int { > > fmt.Println("Init B") > > return A + 1 > > } > > > > func initC() int { > > fmt.Println("Init C") > > return A > > } > > > > Output > > Init A > > Init B > > Init C > > 1 2 1 > > > > I observed this behavior in multiple versions of Go, including: > > - go1.16.4 darwin/amd64 > > - go1.17.2 linux/amd64 > > - go1.18 linux/amd64 > > > > Is this the expected behavior? Am I overlooking any details in the Go > language specification or in the Go memory model? Or is this a bug in the > compiler? > > I think you're right: I think this is a bug. > > Interestingly, I think the runtime package may rely on this bug. In > the runtime package I see > > var maxSearchAddr = maxOffAddr > var maxOffAddr = offAddr{(((1 << heapAddrBits) - 1) + arenaBaseOffset) > & uintptrMask} > > and pageAlloc.Init, which is called by mheap.init which is called by > mallocinit which is called by schedinit before package initializers > are run. So the compiler is implementing an optimization to > initialize maxSearchAddr before running package initialization > routines, which I suppose is OK provided it that it can prove that the > variable is never set by any function run during package > initialization. > > Want to open a bug report at https://go.dev/issue? Thanks. > > Ian > -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/f37ab0a1-d287-405f-9e2a-514ab6e60acan%40googlegroups.com.