From a43669843b155ddb575d95acdb72dc62a1434efd Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Tue, 20 May 2014 13:51:39 -0700 Subject: [PATCH] spec: clarify section on package initialization - split description of package initialization and program execution - better grouping of concerns in section on package initialization - more explicit definition of what constitues a dependency - removed language about constant dependencies - they are computed at compile-time and not initialized at run-time - clarified that independent variables are initialized in declaration order (rather than reference order) Note that the last clarification is what distinguishes gc and gccgo at the moment: gc uses reference order (i.e., order in which variables are referenced in initialization expressions), while gccgo uses declaration order for independent variables. Not a language change. But adopting this CL will clarify what constitutes a dependency. Fixes #6703. LGTM=adonovan, r, iant, rsc R=r, rsc, iant, ken, adonovan CC=golang-codereviews https://golang.org/cl/99020043 --- doc/go_spec.html | 162 +++++++++++++++++++++++++++++++---------------- 1 file changed, 108 insertions(+), 54 deletions(-) diff --git a/doc/go_spec.html b/doc/go_spec.html index eef4921d3e9..01770395fde 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -1,6 +1,6 @@ @@ -1533,6 +1533,9 @@ no identifier may be declared in both the file and package block.

The blank identifier may be used like any other identifier in a declaration, but it does not introduce a binding and thus is not declared. +In the package block, the identifier init may only be used for +init function declarations, +and like the blank identifier it does not introduce a new binding.

@@ -4014,7 +4017,7 @@ precision.
 

Order of evaluation

-At package level, initialization dependencies +At package level, initialization dependencies determine the evaluation order of individual initialization expressions in variable declarations. Otherwise, when evaluating the operands of an @@ -5907,62 +5910,125 @@ The same would also be true after var t T

-

Program execution

+

Package initialization

-A package with no imports is initialized by assigning initial values to -all its package-level variables -and then calling any -package-level function with the name and signature of +Within a package, package-level variables are initialized according +to their dependencies: if a variable x depends on +a variable y, x will be initialized after +y.

+ +

+Dependency analysis does not rely on the actual values of the +variables, only on lexical references to them in the source, +analyzed transitively. For instance, a variable x's +initialization expression +may refer to a function whose body refers to variable y; +if so, x depends on y. +Specifically: +

+ + + +

+Dependency analysis is performed per package; only references referring +to variables, functions, and methods declared in the current package +are considered. +It is an error if variable dependencies form a cycle +(but dependency cycles containing no variables are permitted). +If two variables are independent of each other, +they are initialized in the order they are declared +in the source, possibly in multiple files, as presented to the compiler. +

+ +

+For example, given the declarations +

+
-func init()
+var (
+	a = c + b
+	b = f()
+	c = f()
+	d = 3
+)
+
+func f() int {
+	d++
+	return d
+}
 
+

-defined in its source. -A package-scope or file-scope identifier -with name init may only be -declared to be a function with this signature. -Multiple such functions may be defined, even -within a single source file; they execute -in unspecified order. +the initialization order is d, b, c, a. +Since b and c are independent of each other, they are +initialized in declaration order (b before c).

+

-Within a package, package-level variables are initialized, -and constant values are determined, according to -order of reference: if the initializer of A -depends on B, A -will be set after B. -Dependency analysis does not depend on the actual values -of the items being initialized, only on their appearance -in the source. -A -depends on B if the value of A -contains a mention of B, contains a value -whose initializer -mentions B, or mentions a function that -mentions B, recursively. -It is an error if such dependencies form a cycle. -If two items are not interdependent, they will be initialized -in the order they appear in the source, possibly in multiple files, -as presented to the compiler. -Since the dependency analysis is done per package, it can produce -unspecified results if A's initializer calls a function defined -in another package that refers to B. +Variables may also be initialized using functions named init +declared in the package block, with no arguments and no result parameters.

+ +
+func init() { … }
+
+

-An init function cannot be referred to from anywhere -in a program. In particular, init cannot be called explicitly, -nor can a pointer to init be assigned to a function variable. +Multiple such functions may be defined, even within a single +source file. The init identifier is not +declared and thus +init functions cannot be referred to from anywhere +in a program.

+

+A package with no imports is initialized by assigning initial values +to all its package-level variables followed by calling all init +functions in unspecified order. If a package has imports, the imported packages are initialized before initializing the package itself. If multiple packages import -a package P, P will be initialized only once. +a package, the imported package will be initialized only once. +The importing of packages, by construction, guarantees that there +can be no cyclic initialization dependencies.

+

-The importing of packages, by construction, guarantees that there can -be no cyclic dependencies in initialization. +Package initialization—variable initialization and the invocation of +init functions—happens in a single goroutine, +sequentially, one package at a time. +An init function may launch other goroutines, which can run +concurrently with the initialization code. However, initialization +always sequences +the init functions: it will not invoke the next one +until the previous one has returned.

+ + +

Program execution

A complete program is created by linking a single, unimported package called the main package with all the packages it imports, transitively. @@ -5983,18 +6049,6 @@ When that function invocation returns, the program exits. It does not wait for other (non-main) goroutines to complete.

-

-Package initialization—variable initialization and the invocation of -init functions—happens in a single goroutine, -sequentially, one package at a time. -An init function may launch other goroutines, which can run -concurrently with the initialization code. However, initialization -always sequences -the init functions: it will not start the next -init until -the previous one has returned. -

-

Errors