1
0
mirror of https://github.com/golang/go synced 2024-11-22 01:34:41 -07:00

go spec: clarify semantics of range clause

This CL proposes some subtle language changes
in an attempt to clarify the semantics of range
clauses and simplify uses of maps.

- nil maps behave like empty maps; but attempting
  to set a value in a nil map causes a run-time panic
- nil channels are never ready for communication;
  sending or reading from a nil channel blocks forever
- if there is only one index iteration variable in a
  range clause and len(range expression) would be a constant,
  the range expression is not evaluated.
  (was discrepancy with len/cap before)
- the notion of what is a constant expression len(x)
  for (pointer to) arrays x has been generalized and
  simplified (can still be syntactically decided)
  (before: more restrictive syntactic rule that was not
  consistently implemented)

Fixes #1713.

R=r, rsc, iant, ken2, r2, bradfitz, rog
CC=golang-dev
https://golang.org/cl/4444050
This commit is contained in:
Robert Griesemer 2011-05-12 09:15:59 -07:00
parent 82d1a9dce7
commit 5473103666

View File

@ -1,5 +1,5 @@
<!-- title The Go Programming Language Specification --> <!-- title The Go Programming Language Specification -->
<!-- subtitle Version of May 4, 2011 --> <!-- subtitle Version of May 12, 2011 -->
<!-- <!--
TODO TODO
@ -1174,8 +1174,10 @@ make(map[string] int, 100)
<p> <p>
The initial capacity does not bound its size: The initial capacity does not bound its size:
maps grow to accommodate the number of items maps grow to accommodate the number of items
stored in them. stored in them, with the exception of <code>nil</code> maps.
</p> A <code>nil</code> map is equivalent to an empty map except that no elements
may be added.
</code>
<h3 id="Channel_types">Channel types</h3> <h3 id="Channel_types">Channel types</h3>
@ -1234,6 +1236,7 @@ succeed without blocking if the buffer is not full (sends) or not empty (receive
and elements are received in the order they are sent. and elements are received in the order they are sent.
If the capacity is zero or absent, the communication succeeds only when both a sender and If the capacity is zero or absent, the communication succeeds only when both a sender and
receiver are ready. receiver are ready.
A <code>nil</code> channel is never ready for communication.
</p> </p>
<p> <p>
@ -1968,7 +1971,7 @@ package, which means that it must begin with a Unicode upper case letter.
math.Sin math.Sin
</pre> </pre>
<!--- <!--
<p> <p>
<span class="alert">TODO: Unify this section with Selectors - it's the same syntax.</span> <span class="alert">TODO: Unify this section with Selectors - it's the same syntax.</span>
</p> </p>
@ -2336,7 +2339,7 @@ p.M0 // ((*p).T0).M0
</pre> </pre>
<!--- <!--
<span class="alert"> <span class="alert">
TODO: Specify what happens to receivers. TODO: Specify what happens to receivers.
</span> </span>
@ -2369,7 +2372,7 @@ or for <code>a</code> of type <code>S</code> where <code>S</code> is a <a href="
<li><code>x</code> must be an integer value and <code>0 &lt;= x &lt; len(a)</code></li> <li><code>x</code> must be an integer value and <code>0 &lt;= x &lt; len(a)</code></li>
<li><code>a[x]</code> is the array element at index <code>x</code> and the type of <li><code>a[x]</code> is the array element at index <code>x</code> and the type of
<code>a[x]</code> is the element type of <code>A</code></li> <code>a[x]</code> is the element type of <code>A</code></li>
<li>if the index <code>x</code> is out of range, <li>if <code>a</code> is <code>nil</code> or if the index <code>x</code> is out of range,
a <a href="#Run_time_panics">run-time panic</a> occurs</li> a <a href="#Run_time_panics">run-time panic</a> occurs</li>
</ul> </ul>
@ -2397,7 +2400,7 @@ where <code>M</code> is a <a href="#Map_types">map type</a>:
<li>if the map contains an entry with key <code>x</code>, <li>if the map contains an entry with key <code>x</code>,
<code>a[x]</code> is the map value with key <code>x</code> <code>a[x]</code> is the map value with key <code>x</code>
and the type of <code>a[x]</code> is the value type of <code>M</code></li> and the type of <code>a[x]</code> is the value type of <code>M</code></li>
<li>if the map does not contain such an entry, <li>if the map is <code>nil</code> or does not contain such an entry,
<code>a[x]</code> is the <a href="#The_zero_value">zero value</a> <code>a[x]</code> is the <a href="#The_zero_value">zero value</a>
for the value type of <code>M</code></li> for the value type of <code>M</code></li>
</ul> </ul>
@ -2426,7 +2429,7 @@ where the result of the index expression is a pair of values with types
</p> </p>
<p> <p>
Similarly, if an assignment to a map has the special form Similarly, if an assignment to a map element has the special form
</p> </p>
<pre> <pre>
@ -2440,6 +2443,11 @@ the entry for key <code>x</code> is deleted from the map; if
a regular assignment to an element of the map. a regular assignment to an element of the map.
</p> </p>
<p>
Assigning to an element of a <code>nil</code> map causes a
<a href="#Run_time_panics">run-time panic</a>.
</p>
<h3 id="Slices">Slices</h3> <h3 id="Slices">Slices</h3>
@ -3043,6 +3051,7 @@ For an operand <code>ch</code> of <a href="#Channel_types">channel type</a>,
the value of the receive operation <code>&lt;-ch</code> is the value received the value of the receive operation <code>&lt;-ch</code> is the value received
from the channel <code>ch</code>. The type of the value is the element type of from the channel <code>ch</code>. The type of the value is the element type of
the channel. The expression blocks until a value is available. the channel. The expression blocks until a value is available.
Receiving from a <code>nil</code> channel blocks forever.
</p> </p>
<pre> <pre>
@ -3070,12 +3079,7 @@ or is a <a href="#The_zero_value">zero value</a> returned
because the channel is closed and empty (<code>false</code>). because the channel is closed and empty (<code>false</code>).
</p> </p>
<p> <!--
Receiving from a <code>nil</code> channel causes a
<a href="#Run_time_panics">run-time panic</a>.
</p>
<!---
<p> <p>
<span class="alert">TODO: Probably in a separate section, communication semantics <span class="alert">TODO: Probably in a separate section, communication semantics
need to be presented regarding send, receive, select, and goroutines.</span> need to be presented regarding send, receive, select, and goroutines.</span>
@ -3449,7 +3453,7 @@ int8(^1) // same as int8(-2)
^int8(1) // same as -1 ^ int8(1) = -2 ^int8(1) // same as -1 ^ int8(1) = -2
</pre> </pre>
<!--- <!--
<p> <p>
<span class="alert"> <span class="alert">
TODO: perhaps ^ should be disallowed on non-uints instead of assuming twos complement. TODO: perhaps ^ should be disallowed on non-uints instead of assuming twos complement.
@ -3575,17 +3579,13 @@ begins. Communication blocks until the send can proceed, at which point the
value is transmitted on the channel. value is transmitted on the channel.
A send on an unbuffered channel can proceed if a receiver is ready. A send on an unbuffered channel can proceed if a receiver is ready.
A send on a buffered channel can proceed if there is room in the buffer. A send on a buffered channel can proceed if there is room in the buffer.
A send on a <code>nil</code> channel blocks forever.
</p> </p>
<pre> <pre>
ch &lt;- 3 ch &lt;- 3
</pre> </pre>
<p>
Sending to a <code>nil</code> channel causes a
<a href="#Run_time_panics">run-time panic</a>.
</p>
<h3 id="IncDec_statements">IncDec statements</h3> <h3 id="IncDec_statements">IncDec statements</h3>
@ -3984,10 +3984,14 @@ As with an assignment, the operands on the left must be
<a href="#Address_operators">addressable</a> or map index expressions; they <a href="#Address_operators">addressable</a> or map index expressions; they
denote the iteration variables. If the range expression is a channel, only denote the iteration variables. If the range expression is a channel, only
one iteration variable is permitted, otherwise there may be one or two. one iteration variable is permitted, otherwise there may be one or two.
If the second iteration variable is the <a href="#Blank_identifier">blank identifier</a>,
the range clause is equivalent to the same clause with only the first variable present.
</p> </p>
<p> <p>
The range expression is evaluated once before beginning the loop. The range expression is evaluated once before beginning the loop
except if the expression is an array, in which case, depending on
the expression, it might not be evaluated (see below).
Function calls on the left are evaluated once per iteration. Function calls on the left are evaluated once per iteration.
For each iteration, iteration values are produced as follows: For each iteration, iteration values are produced as follows:
</p> </p>
@ -4003,8 +4007,11 @@ channel c chan E element e E
<ol> <ol>
<li> <li>
For an array or slice value, the index iteration values are produced in For an array, pointer to array, or slice value <code>a</code>, the index iteration
increasing order, starting at element index 0. values are produced in increasing order, starting at element index 0. As a special
case, if only the first iteration variable is present, the range loop produces
iteration values from 0 up to <code>len(a)</code> and does not index into the array
or slice itself. For a <code>nil</code> slice, the number of iterations is 0.
</li> </li>
<li> <li>
@ -4023,13 +4030,14 @@ The iteration order over maps is not specified.
If map entries that have not yet been reached are deleted during iteration, If map entries that have not yet been reached are deleted during iteration,
the corresponding iteration values will not be produced. If map entries are the corresponding iteration values will not be produced. If map entries are
inserted during iteration, the behavior is implementation-dependent, but the inserted during iteration, the behavior is implementation-dependent, but the
iteration values for each entry will be produced at most once. iteration values for each entry will be produced at most once. If the map
is <code>nil</code>, the number of iterations is 0.
</li> </li>
<li> <li>
For channels, the iteration values produced are the successive values sent on For channels, the iteration values produced are the successive values sent on
the channel until the channel is closed the channel until the channel is <a href="#Close">closed</a>. If the channel
<a href="#Close"><code>close</code></a>). is <code>nil</code>, the range expression blocks forever.
</li> </li>
</ol> </ol>
@ -4048,9 +4056,17 @@ after execution their values will be those of the last iteration.
</p> </p>
<pre> <pre>
var testdata *struct {
a *[7]int
}
for i, _ := range testdata.a {
// testdata.a is never evaluated; len(testdata.a) is constant
// i ranges from 0 to 6
f(i)
}
var a [10]string var a [10]string
m := map[string]int{"mon":0, "tue":1, "wed":2, "thu":3, "fri":4, "sat":5, "sun":6} m := map[string]int{"mon":0, "tue":1, "wed":2, "thu":3, "fri":4, "sat":5, "sun":6}
for i, s := range a { for i, s := range a {
// type of i is int // type of i is int
// type of s is string // type of s is string
@ -4065,6 +4081,11 @@ for key, val = range m {
} }
// key == last map key encountered in iteration // key == last map key encountered in iteration
// val == map[key] // val == map[key]
var ch chan Work = producer()
for w := range ch {
doWork(w)
}
</pre> </pre>
@ -4247,7 +4268,7 @@ func (devnull) Write(p []byte) (n int, _ os.Error) {
Regardless of how they are declared, all the result values are initialized to the zero values for their type (§<a href="#The_zero_value">The zero value</a>) upon entry to the function. Regardless of how they are declared, all the result values are initialized to the zero values for their type (§<a href="#The_zero_value">The zero value</a>) upon entry to the function.
</p> </p>
<!--- <!--
<p> <p>
<span class="alert"> <span class="alert">
TODO: Define when return is required.<br /> TODO: Define when return is required.<br />
@ -4332,7 +4353,7 @@ L:
<p> <p>
is erroneous because the jump to label <code>L</code> skips is erroneous because the jump to label <code>L</code> skips
the creation of <code>v</code>. the creation of <code>v</code>.
<!--- <!--
(<span class="alert">TODO: Eliminate in favor of used and not set errors?</span>) (<span class="alert">TODO: Eliminate in favor of used and not set errors?</span>)
--> -->
</p> </p>
@ -4439,17 +4460,17 @@ The implementation guarantees that the result always fits into an <code>int</cod
</p> </p>
<pre class="grammar"> <pre class="grammar">
Call Argument type Result Call Argument type Result
len(s) string type string length in bytes len(s) string type string length in bytes
[n]T, *[n]T array length (== n) [n]T, *[n]T array length (== n)
[]T slice length []T slice length
map[K]T map length (number of defined keys) map[K]T map length (number of defined keys)
chan T number of elements queued in channel buffer chan T number of elements queued in channel buffer
cap(s) [n]T, *[n]T array length (== n) cap(s) [n]T, *[n]T array length (== n)
[]T slice capacity []T slice capacity
chan T channel buffer capacity chan T channel buffer capacity
</pre> </pre>
<p> <p>
@ -4467,20 +4488,17 @@ The length and capacity of a <code>nil</code> slice, map, or channel are 0.
</p> </p>
<p> <p>
The expression The expression <code>len(s)</code> is <a href="#Constants">constant</a> if
<code>len(s)</code> is a <code>s</code> is a string constant. The expressions <code>len(s)</code> and
<a href="#Constants">constant</a> if <code>s</code> is a string constant. <code>cap(s)</code> are constants if the type of <code>s</code> is an array
The expressions or pointer to an array and the expression <code>s</code> does not contain
<code>len(s)</code> and <a href="#Receive_operator">channel receives</a> or
<code>cap(s)</code> are <a href="#Calls">function calls</a>; in this case <code>s</code> is not evaluated.
constants if <code>s</code> is an (optionally parenthesized) Otherwise, invocations of <code>len</code> and <code>cap</code> are not
identifier or constant and <code>s</code> is evaluated.
<a href="#Qualified_identifiers">qualified identifier</a>
denoting an array or pointer to array.
Otherwise invocations of <code>len</code> and <code>cap</code> are not
constant.
</p> </p>
<h3 id="Allocation">Allocation</h3> <h3 id="Allocation">Allocation</h3>
<p> <p>
@ -5169,5 +5187,8 @@ The following minimal alignment properties are guaranteed:
<h2 id="Implementation_differences"><span class="alert">Implementation differences - TODO</span></h2> <h2 id="Implementation_differences"><span class="alert">Implementation differences - TODO</span></h2>
<ul> <ul>
<li><span class="alert">Implementation does not honor the restriction on goto statements and targets (no intervening declarations).</span></li> <li><span class="alert">The restriction on <code>goto</code> statements and targets (no intervening declarations) is not honored.</span></li>
<li><span class="alert"><code>len(a)</code> is only a constant if <code>a</code> is a (qualified) identifier denoting an array or pointer to an array.</span></li>
<li><span class="alert"><code>nil</code> maps are not treated like empty maps.</span></li>
<li><span class="alert">Trying to send/receive from a <code>nil</code> channel causes a run-time panic.</span></li>
</ul> </ul>