From 30a1a8c92251941dd850d66ec434231cc1140fb3 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Tue, 16 Dec 2008 11:38:56 -0800 Subject: [PATCH] language for range clause (I have deliberately left away the forms w/ := or = and the forms with :) R=r DELTA=106 (44 added, 13 deleted, 49 changed) OCL=21192 CL=21283 --- doc/go_spec.txt | 141 +++++++++++++++++++++++++++++------------------- 1 file changed, 86 insertions(+), 55 deletions(-) diff --git a/doc/go_spec.txt b/doc/go_spec.txt index 2c97713f6ff..58c20126064 100644 --- a/doc/go_spec.txt +++ b/doc/go_spec.txt @@ -28,7 +28,6 @@ Timeline (9/5/08): Missing: [ ] partial export of structs, methods -[ ] range statement: to be defined more reasonably [ ] packages of multiple files [ ] Helper syntax for composite types: allow names/indices for maps/arrays, remove need for type in elements of composites @@ -56,7 +55,6 @@ Open issues: [ ] old-style export decls (still needed, but ideally should go away) [ ] like to have assert() in the language, w/ option to disable code gen for it [ ] composite types should uniformly create an instance instead of a pointer -[ ] semantics of statements [ ] need for type switch? (or use type guard with ok in tuple assignment?) [ ] do we need anything on package vs file names? [ ] type switch or some form of type test needed @@ -93,6 +91,8 @@ Decisions in need of integration into the doc: Closed: +[x] semantics of statements - we just need to fill in the language, the semantics is mostly clear +[x] range statement: to be defined more reasonably [x] need to be specific on (unsigned) integer operations: one must be able to rely on wrap-around on overflow [x] global var decls: "var a, b, c int = 0, 0, 0" is ok, but "var a, b, c = 0, 0, 0" is not @@ -198,7 +198,6 @@ Contents If statements Switch statements For statements - Range statements Go statements Select statements Return statements @@ -583,7 +582,9 @@ same identifier declared in an outer block. 3. The scope of a constant or variable extends textually from after the declaration to the end of the innermost surrounding - block. + block. If the variable is declared in the init statement of an + if, for, or switch statement, the innermost surrounding block + is the block associated with the respective statement. 4. The scope of a parameter or result identifier is the body of the corresponding function. @@ -2369,8 +2370,7 @@ Statements control execution. Statement = Declaration | LabelDecl | EmptyStat | SimpleStat | GoStat | ReturnStat | BreakStat | ContinueStat | GotoStat | - FallthroughStat | Block | IfStat | SwitchStat | SelectStat | ForStat | - RangeStat . + FallthroughStat | Block | IfStat | SwitchStat | SelectStat | ForStat . SimpleStat = ExpressionStat | IncDecStat | Assignment | SimpleVarDecl . @@ -2589,68 +2589,99 @@ If the expression is omitted, it is equivalent to "true". For statements ---- -For statements are a combination of the "for" and "while" loops of C. +A for statement specifies repeated execution of a block. The iteration is +controlled by a condition, a for clause, or a range clause. - ForStat = "for" [ Condition | ForClause ] Block . - ForClause = [ InitStat ] ";" [ Condition ] ";" [ PostStat ] . - - InitStat = SimpleStat . + ForStat = "for" [ Condition | ForClause | RangeClause ] Block . Condition = Expression . - PostStat = SimpleStat . -A SimpleStat is a simple statement such as an assignment, a SimpleVarDecl, -or an increment or decrement statement. Therefore one may declare a loop -variable in the init statement. - - for i := 0; i < 10; i++ { - print(i, "\n") - } - -A for statement with just a condition executes until the condition becomes -false. Thus it is the same as C's while statement. +In its simplest form, a for statement specifies the repeated execution of +a block as long as a condition evaluates to true. The condition is evaluated +before each iteration. The type of the condition expression must be boolean. +If the condition is absent, it is equivalent to "true". for a < b { a *= 2 } -If the condition is absent, it is equivalent to "true". +A for statement with a for clause is also controlled by its condition, but +additionally it may specify an init and post statement, such as an assignment, +an increment or decrement statement. The init statement may also be a (simple) +variable declaration; no variables can be declared in the post statement. - for { - f() + ForClause = [ InitStat ] ";" [ Condition ] ";" [ PostStat ] . + InitStat = SimpleStat . + PostStat = SimpleStat . + +For instance, one may declare an iteration variable in the init statement: + + for i := 0; i < 10; i++ { + f(i) + } + +If present, the init statement is executed once before commencing the iteration; +the post statement is executed after each execution of the statement block (and +only if the block was executed). The scope of any variable declared in the init +statement ends with the end of the for statement block ($Declarations and scope +rules, Rule 3). + +The init and post statement as well as the condition may be omitted; however +if either the init or post statement are present, the separating semicolons +must be present. If the condition is absent, it is equivalent to "true". +The following statements are equivalent: + + for ; cond ; { S() } is the same as for cond { S() } + for true { S() } is the same as for { S() } + +Alternatively, a for statement may be controlled by a range clause. A +range clause specifies iteration through all entries of an array or map. +For each entry it first assigns the current index or key to an iteration +variable - or the current (index, element) or (key, value) pair to a pair +of iteration variables - and then executes the block. Iteration terminates +when all entries have been processed, or if the for statement is terminated +early, for instance by a break or return statement. + + RangeClause = IdentifierList ( "=" | ":=" ) "range" Expression . + +The type of the right-hand expression in the range clause must be an array or +map, or a pointer to an array or map. If it is a pointer, it must not be nil. +The left-hand identifier list must contain one or two identifiers denoting the +iteration variables. The first variable is set to the current array index or +map key, and the second variable, if present, is set to the corresponding +array element or map value. The types of the array index (int) and element, +or of the map key and value respectively, must be assignment-compatible to +the iteration variables. + +The iteration variables may be declared by the range clause (":="), in which +case their scope ends at the end of the for statement block ($Declarations and +scope rules, Rule 3). In this case their types are the array index and element, +or the map key and value types, respectively. + + var a [10]string; + m := map[string]int{"mon":0, "tue":1, "wed":2, "thu":3, "fri":4, "sat":5, "sun":6}; + + for i, s := range a { + // type of i is int + // type of s is string + // s == a[i] + g(i, s) } - -Range statements ----- - -Range statements are a special control structure for iterating over -the contents of arrays and maps. - - RangeStat = "range" IdentifierList ":=" RangeExpression Block . - RangeExpression = Expression . - -A range expression must evaluate to an array, map or string. The identifier list must contain -either one or two identifiers. If the range expression is a map, a single identifier is declared -to range over the keys of the map; two identifiers range over the keys and corresponding -values. For arrays and strings, the behavior is analogous for integer indices (the keys) and -array elements (the values). - - a := []int(1, 2, 3); - m := [string]map int("fo",2, "foo",3, "fooo",4) - - range i := a { - f(a[i]); + var key string; + var val interface {}; // value type of m is assignment-compatible to val + for key, value = range m { + h(key, value) } + // key == last map key encountered in iteration + // val == map[key] - range i, v := a { - f(v); - } - - range k, v := m { - assert(len(k) == v); - } - -TODO: is this right? +If map entries that have not yet been processed are deleted during iteration, +they will not be processed. If map entries are inserted during iteration, the +behavior is implementation-dependent. Likewise, if the range expression is a +pointer variable, the behavior of assigning to that variable is implementation- +dependent. Assigning to the iteration variables during iteration simply changes +the values of those variables for the current iteration; it does not affect any +subsequent iterations. Go statements