BTW, the rewritten version outputs Init A Init B Init C 1 4 3
On my machine (go1.18 linux/amd64). On Thursday, March 24, 2022 at 7:30:37 PM UTC+8 tapi...@gmail.com wrote: > > 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/47e3c43d-65f6-4743-b9b9-60626c9142e0n%40googlegroups.com.