Go

Package initialization order: what does this program print?

Question 515HardGo 1.22 to 1.25
package main

import "fmt"

var (
    a = c + b
    b = f("b")
    c = f("c")
    d = f("d")
)

func f(s string) int {
    fmt.Print(s, " ")
    return len(s)
}

func init() { fmt.Print("init1 ") }
func init() { fmt.Print("init2 ") }

func main() {
    fmt.Println("main", a, d)
}

Output: b c d init1 init2 main 2 1.

Package-level variables are initialized by dependency, not simply top to bottom. The spec repeatedly picks the earliest variable, in declaration order, whose dependencies are all initialized. a depends on c and b, so it waits. b is ready and runs first, then c (the operand order inside c + b does not matter). Then a becomes ready and gets 1 + 1 = 2, and after that d runs. A dependency cycle between package variables is a compile error (initialization cycle).

All variables are initialized before any init function runs. A package may have several init functions, even in one file. They run in the order they appear, with files presented to the compiler in file-name order. Every imported package is fully initialized first, which is why fmt.Print works inside f. Since Go 1.21 the order across packages is precisely defined as well (sorted by import path, with dependencies first).

Code-review angle: init functions that read files, open connections, or rely on another package's init side effects make code hard to test and cause surprising order bugs. Prefer explicit constructors, or sync.OnceValue for lazy globals.

More on Tricky Output & Code-Review Puzzles

All 38 Tricky Output & Code-Review Puzzles questions