Skip to content

Commit 451cf3e

Browse files
committed
spec: clarify language on package-level variable initialization
The very first paragraph on "Package initialization" stated that "variables are initialized in declaration order, but after any variables they might depend on". This phrasing was easily misread as "declaration order is the first sorting criteria" and then contradicted what the subsequent paragraphs spelled out in precise detail. Instead, variable initialization proceeds by repeatedly determining a set of ready to initialize variables, and then selecting from that set the variable declared earliest. That is, declaration order is the second sorting criteria. Also, for the purpose of variable initialization, declarations introducing blank (_) variables are considered like any other variables (their initialization expressions may have side-effects and affect initialization order), even though blank identifiers are not "declared". This CL adds clarifying language regarding these two issues and the supporting example. Both gccgo and go/types implement this behavior. cmd/compile has a long-standing issue (#22326). The spec also did not state in which order multiple variables initialized by a single (multi-value) initialization expression are handled. This CL adds a clarifying paragraph: If any such variable is initialized, all that declaration's variables are initialized at the same time. This behavior matches user expectation: We are not expecting to observe partially initialized sets of variables in declarations such as "var a, b, c = f()". It also matches existing cmd/compile and go/types (but not gccgo) behavior. Finally, cmd/compile, gccgo, and go/types produce different initialization orders in (esoteric) cases where hidden (not detected with existing rules) dependencies exist. Added a sentence and example clarifying how much leeway compilers have in those situations. The goal is to preserve the ability to use static initialization while at the same time maintain the relative initialization order of variables with detected dependencies. Fixes #31292. Updates #22326. Change-Id: I0a369abff8cfce27afc975998db875f5c580caa2 Reviewed-on: https://go-review.googlesource.com/c/go/+/175980 Reviewed-by: Ian Lance Taylor <[email protected]> Reviewed-by: Matthew Dempsky <[email protected]>
1 parent 5d98330 commit 451cf3e

File tree

1 file changed

+59
-15
lines changed

1 file changed

+59
-15
lines changed

doc/go_spec.html

+59-15
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<!--{
22
"Title": "The Go Programming Language Specification",
3-
"Subtitle": "Version of March 13, 2019",
3+
"Subtitle": "Version of May 13, 2019",
44
"Path": "/ref/spec"
55
}-->
66

@@ -6362,16 +6362,16 @@ <h3 id="The_zero_value">The zero value</h3>
63626362
<h3 id="Package_initialization">Package initialization</h3>
63636363

63646364
<p>
6365-
Within a package, package-level variables are initialized in
6366-
<i>declaration order</i> but after any of the variables
6367-
they <i>depend</i> on.
6365+
Within a package, package-level variable initialization proceeds stepwise,
6366+
with each step selecting the variable earliest in <i>declaration order</i>
6367+
which has no dependencies on uninitialized variables.
63686368
</p>
63696369

63706370
<p>
63716371
More precisely, a package-level variable is considered <i>ready for
63726372
initialization</i> if it is not yet initialized and either has
63736373
no <a href="#Variable_declarations">initialization expression</a> or
6374-
its initialization expression has no dependencies on uninitialized variables.
6374+
its initialization expression has no <i>dependencies</i> on uninitialized variables.
63756375
Initialization proceeds by repeatedly initializing the next package-level
63766376
variable that is earliest in declaration order and ready for initialization,
63776377
until there are no variables ready for initialization.
@@ -6383,6 +6383,23 @@ <h3 id="Package_initialization">Package initialization</h3>
63836383
and the program is not valid.
63846384
</p>
63856385

6386+
<p>
6387+
Multiple variables on the left-hand side of a variable declaration initialized
6388+
by single (multi-valued) expression on the right-hand side are initialized
6389+
together: If any of the variables on the left-hand side is initialized, all
6390+
those variables are initialized in the same step.
6391+
</p>
6392+
6393+
<pre>
6394+
var x = a
6395+
var a, b = f() // a and b are initialized together, before x is initialized
6396+
</pre>
6397+
6398+
<p>
6399+
For the purpose of package initialization, <a href="#Blank_identifier">blank</a>
6400+
variables are treated like any other variables in declarations.
6401+
</p>
6402+
63866403
<p>
63876404
The declaration order of variables declared in multiple files is determined
63886405
by the order in which the files are presented to the compiler: Variables
@@ -6424,22 +6441,16 @@ <h3 id="Package_initialization">Package initialization</h3>
64246441
</li>
64256442
</ul>
64266443

6427-
<p>
6428-
Dependency analysis is performed per package; only references referring
6429-
to variables, functions, and methods declared in the current package
6430-
are considered.
6431-
</p>
6432-
64336444
<p>
64346445
For example, given the declarations
64356446
</p>
64366447

64376448
<pre>
64386449
var (
6439-
a = c + b
6440-
b = f()
6441-
c = f()
6442-
d = 3
6450+
a = c + b // == 9
6451+
b = f() // == 4
6452+
c = f() // == 5
6453+
d = 3 // == 5 after initialization has finished
64436454
)
64446455

64456456
func f() int {
@@ -6450,6 +6461,39 @@ <h3 id="Package_initialization">Package initialization</h3>
64506461

64516462
<p>
64526463
the initialization order is <code>d</code>, <code>b</code>, <code>c</code>, <code>a</code>.
6464+
Note that the order of subexpressions in initialization expressions is irrelevant:
6465+
<code>a = c + b</code> and <code>a = b + c</code> result in the same initialization
6466+
order in this example.
6467+
</p>
6468+
6469+
<p>
6470+
Dependency analysis is performed per package; only references referring
6471+
to variables, functions, and (non-interface) methods declared in the current
6472+
package are considered. If other, hidden, data dependencies exists between
6473+
variables, the initialization order between those variables is unspecified.
6474+
</p>
6475+
6476+
<p>
6477+
For instance, given the declarations
6478+
</p>
6479+
6480+
<pre>
6481+
var x = I(T{}).ab() // x has an undetected, hidden dependency on a and b
6482+
var _ = sideEffect() // unrelated to x, a, or b
6483+
var a = b
6484+
var b = 42
6485+
6486+
type I interface { ab() []int }
6487+
type T struct{}
6488+
func (T) ab() []int { return []int{a, b} }
6489+
</pre>
6490+
6491+
<p>
6492+
the variable <code>a</code> will be initialized after <code>b</code> but
6493+
whether <code>x</code> is initialized before <code>b</code>, between
6494+
<code>b</code> and <code>a</code>, or after <code>a</code>, and
6495+
thus also the moment at which <code>sideEffect()</code> is called (before
6496+
or after <code>x</code> is initialized) is not specified.
64536497
</p>
64546498

64556499
<p>

0 commit comments

Comments
 (0)