mirror of
https://github.com/golang/go
synced 2024-11-23 07:30:05 -07:00
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
This commit is contained in:
parent
4d36ad7791
commit
a43669843b
162
doc/go_spec.html
162
doc/go_spec.html
@ -1,6 +1,6 @@
|
|||||||
<!--{
|
<!--{
|
||||||
"Title": "The Go Programming Language Specification",
|
"Title": "The Go Programming Language Specification",
|
||||||
"Subtitle": "Version of May 19, 2014",
|
"Subtitle": "Version of May 20, 2014",
|
||||||
"Path": "/ref/spec"
|
"Path": "/ref/spec"
|
||||||
}-->
|
}-->
|
||||||
|
|
||||||
@ -1533,6 +1533,9 @@ no identifier may be declared in both the file and package block.
|
|||||||
<p>
|
<p>
|
||||||
The <a href="#Blank_identifier">blank identifier</a> may be used like any other identifier
|
The <a href="#Blank_identifier">blank identifier</a> may be used like any other identifier
|
||||||
in a declaration, but it does not introduce a binding and thus is not declared.
|
in a declaration, but it does not introduce a binding and thus is not declared.
|
||||||
|
In the package block, the identifier <code>init</code> may only be used for
|
||||||
|
<a href="#Package_initialization"><code>init</code> function</a> declarations,
|
||||||
|
and like the blank identifier it does not introduce a new binding.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre class="ebnf">
|
<pre class="ebnf">
|
||||||
@ -4014,7 +4017,7 @@ precision.
|
|||||||
<h3 id="Order_of_evaluation">Order of evaluation</h3>
|
<h3 id="Order_of_evaluation">Order of evaluation</h3>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
At package level, <a href="#Program_execution">initialization dependencies</a>
|
At package level, <a href="#Package_initialization">initialization dependencies</a>
|
||||||
determine the evaluation order of individual initialization expressions in
|
determine the evaluation order of individual initialization expressions in
|
||||||
<a href="#Variable_declarations">variable declarations</a>.
|
<a href="#Variable_declarations">variable declarations</a>.
|
||||||
Otherwise, when evaluating the <a href="#Operands">operands</a> of an
|
Otherwise, when evaluating the <a href="#Operands">operands</a> of an
|
||||||
@ -5907,62 +5910,125 @@ The same would also be true after
|
|||||||
var t T
|
var t T
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<h3 id="Program_execution">Program execution</h3>
|
<h3 id="Package_initialization">Package initialization</h3>
|
||||||
<p>
|
<p>
|
||||||
A package with no imports is initialized by assigning initial values to
|
Within a package, package-level variables are initialized according
|
||||||
all its package-level variables
|
to their <i>dependencies</i>: if a variable <code>x</code> depends on
|
||||||
and then calling any
|
a variable <code>y</code>, <code>x</code> will be initialized after
|
||||||
package-level function with the name and signature of
|
<code>y</code>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Dependency analysis does not rely on the actual values of the
|
||||||
|
variables, only on lexical <i>references</i> to them in the source,
|
||||||
|
analyzed transitively. For instance, a variable <code>x</code>'s
|
||||||
|
<a href="#Variable_declarations">initialization expression</a>
|
||||||
|
may refer to a function whose body refers to variable <code>y</code>;
|
||||||
|
if so, <code>x</code> depends on <code>y</code>.
|
||||||
|
Specifically:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
A reference to a variable or function is an identifier denoting that
|
||||||
|
variable or function.
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
A reference to a method <code>m</code> is a
|
||||||
|
<a href="#Method_values">method value</a> or
|
||||||
|
<a href="#Method_expressions">method expression</a> of the form
|
||||||
|
<code>t.m</code>, where the (static) type of <code>t</code> is
|
||||||
|
not an interface type, and the method <code>m</code> is in the
|
||||||
|
<a href="#Method_sets">method set</a> of <code>t</code>.
|
||||||
|
It is immaterial whether the resulting function value
|
||||||
|
<code>t.m</code> is invoked.
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
A variable, function, or method <code>x</code> depends on a variable
|
||||||
|
<code>y</code> if <code>x</code>'s initialization expression or body
|
||||||
|
(for functions and methods) contains a reference to <code>y</code>
|
||||||
|
or to a function or method that depends on <code>y</code>.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
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.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
For example, given the declarations
|
||||||
|
</p>
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
func init()
|
var (
|
||||||
|
a = c + b
|
||||||
|
b = f()
|
||||||
|
c = f()
|
||||||
|
d = 3
|
||||||
|
)
|
||||||
|
|
||||||
|
func f() int {
|
||||||
|
d++
|
||||||
|
return d
|
||||||
|
}
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
defined in its source.
|
the initialization order is <code>d</code>, <code>b</code>, <code>c</code>, <code>a</code>.
|
||||||
A package-scope or file-scope identifier
|
Since <code>b</code> and <code>c</code> are independent of each other, they are
|
||||||
with name <code>init</code> may only be
|
initialized in declaration order (<code>b</code> before <code>c</code>).
|
||||||
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.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Within a package, package-level variables are initialized,
|
Variables may also be initialized using functions named <code>init</code>
|
||||||
and constant values are determined, according to
|
declared in the package block, with no arguments and no result parameters.
|
||||||
order of reference: if the initializer of <code>A</code>
|
|
||||||
depends on <code>B</code>, <code>A</code>
|
|
||||||
will be set after <code>B</code>.
|
|
||||||
Dependency analysis does not depend on the actual values
|
|
||||||
of the items being initialized, only on their appearance
|
|
||||||
in the source.
|
|
||||||
<code>A</code>
|
|
||||||
depends on <code>B</code> if the value of <code>A</code>
|
|
||||||
contains a mention of <code>B</code>, contains a value
|
|
||||||
whose initializer
|
|
||||||
mentions <code>B</code>, or mentions a function that
|
|
||||||
mentions <code>B</code>, 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 <code>A</code>'s initializer calls a function defined
|
|
||||||
in another package that refers to <code>B</code>.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
func init() { … }
|
||||||
|
</pre>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
An <code>init</code> function cannot be referred to from anywhere
|
Multiple such functions may be defined, even within a single
|
||||||
in a program. In particular, <code>init</code> cannot be called explicitly,
|
source file. The <code>init</code> identifier is not
|
||||||
nor can a pointer to <code>init</code> be assigned to a function variable.
|
<a href="#Declarations_and_scope">declared</a> and thus
|
||||||
|
<code>init</code> functions cannot be referred to from anywhere
|
||||||
|
in a program.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
A package with no imports is initialized by assigning initial values
|
||||||
|
to all its package-level variables followed by calling all <code>init</code>
|
||||||
|
functions in unspecified order.
|
||||||
If a package has imports, the imported packages are initialized
|
If a package has imports, the imported packages are initialized
|
||||||
before initializing the package itself. If multiple packages import
|
before initializing the package itself. If multiple packages import
|
||||||
a package <code>P</code>, <code>P</code> 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.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
The importing of packages, by construction, guarantees that there can
|
Package initialization—variable initialization and the invocation of
|
||||||
be no cyclic dependencies in initialization.
|
<code>init</code> functions—happens in a single goroutine,
|
||||||
|
sequentially, one package at a time.
|
||||||
|
An <code>init</code> function may launch other goroutines, which can run
|
||||||
|
concurrently with the initialization code. However, initialization
|
||||||
|
always sequences
|
||||||
|
the <code>init</code> functions: it will not invoke the next one
|
||||||
|
until the previous one has returned.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
<h3 id="Program_execution">Program execution</h3>
|
||||||
<p>
|
<p>
|
||||||
A complete program is created by linking a single, unimported package
|
A complete program is created by linking a single, unimported package
|
||||||
called the <i>main package</i> with all the packages it imports, transitively.
|
called the <i>main package</i> 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-<code>main</code>) goroutines to complete.
|
It does not wait for other (non-<code>main</code>) goroutines to complete.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
|
||||||
Package initialization—variable initialization and the invocation of
|
|
||||||
<code>init</code> functions—happens in a single goroutine,
|
|
||||||
sequentially, one package at a time.
|
|
||||||
An <code>init</code> function may launch other goroutines, which can run
|
|
||||||
concurrently with the initialization code. However, initialization
|
|
||||||
always sequences
|
|
||||||
the <code>init</code> functions: it will not start the next
|
|
||||||
<code>init</code> until
|
|
||||||
the previous one has returned.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h2 id="Errors">Errors</h2>
|
<h2 id="Errors">Errors</h2>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
Loading…
Reference in New Issue
Block a user