From df3183f528426c675e783ed437d72041b15ebb94 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Thu, 26 Feb 2009 16:37:23 -0800 Subject: [PATCH] finish types. expressions. (they were in pretty good shape; mostly cosmetic and HTML edits) R=gri DELTA=655 (226 added, 97 deleted, 332 changed) OCL=25459 CL=25481 --- doc/go_spec.html | 847 +++++++++++++++++++++++++++-------------------- 1 file changed, 488 insertions(+), 359 deletions(-) diff --git a/doc/go_spec.html b/doc/go_spec.html index e286a4e6ddd..64de93adc6e 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -1735,6 +1735,19 @@ only after their own declaration or forward-declaration (§Forward declarations) Implementation restriction: They can only be declared at package level.

+

+The type of a method is the type of a function with the receiver as first +argument. For instance, the method Scale has type +

+ +
+(p *Point, factor float)
+
+ +

+However, a function declared this way is not a method. +

+

Forward declarations

@@ -1777,164 +1790,176 @@ func F(a int) int {

Expressions

-An expression specifies the computation of a value via the application of -operators and function invocations on operands. An expression has a value and +

+An expression specifies the computation of a value by applying +operators and functions to operands. An expression has a value and a type. -

-The type of a constant expression may be an ideal number. The type of such expressions -is implicitly converted into the 'expected numeric type' required for the expression. -The conversion is legal if the (ideal) expression value is a member of the -set represented by the expected numeric type. In all other cases, and specifically -if the expected type is not a numeric type, the expression is erroneous. -

-For instance, if the expected numeric type is a uint32, any ideal number -which fits into a uint32 without loss of precision can be legally converted. -Thus, the values 991, 42.0, and 1e9 are ok, but -1, 3.14, or 1e100 are not. - - - +

Operands

Operands denote the elementary values in an expression.
-Operand  = Literal | QualifiedIdent | "(" Expression ")" .
-Literal  = BasicLit | CompositeLit | FunctionLit .
-BasicLit = int_lit | float_lit | char_lit | StringLit .
-StringLit = string_lit { string_lit } .
+Operand    = Literal | QualifiedIdent | "(" Expression ")" .
+Literal    = BasicLit | CompositeLit | FunctionLit .
+BasicLit   = int_lit | float_lit | char_lit | StringLit .
+StringLit  = string_lit { string_lit } .
 

Constants

-An operand is called ``constant'' if it is a literal of a basic type -(including the predeclared constants "true" and "false", and the values -denoted by "iota"), the predeclared constant "nil", or a parenthesized +

+An operand is called constant if it is a literal of a basic type +(including the predeclared constants true and false, +and values denoted by iota), +the predeclared constant nil, or a parenthesized constant expression (§Constant expressions). Constants have values that -are known at compile-time. - +are known at compile time. +

Qualified identifiers

-A qualified identifier is an identifier qualified by a package name.

- -TODO(gri) expand this section. - +A qualified identifier is an identifier qualified by a package name prefix. +

-QualifiedIdent = { PackageName "." } identifier .
+QualifiedIdent = [ LocalPackageName "." ] [ PackageName "." ] identifier .
+LocalPackageName = identifier .
 PackageName = identifier .
 
+

+A qualified identifier accesses an identifier in +a separate package. The identifier must be exported by that package, which +means that it must begin with a Unicode upper case letter (§Exported identifiers). +

+

+The LocalPackageName is that of the package in which the qualified identifier +appears and is only necessary to access names hidden by intervening declarations +of a package-level identifier. +

+ +
+Math.Sin
+mypackage.hiddenName
+mypackage.Math.Sin  // if Math is declared in an intervening scope
+

Composite literals

-Literals for composite data structures consist of the type of the value -followed by a braced expression list for array, slice, and structure literals, +

+Composite literals construct values for structs, arrays, slices, and maps +and create a new value each time they are evaluated. +They consist of the type of the value +followed by a parenthesized list of expressions, or a list of expression pairs for map literals. +

-CompositeLit = LiteralType "(" [ ( ExpressionList | ExprPairList ) [ "," ] ] ")" .
-LiteralType = Type | "[" "..." "]" ElementType .
-ExprPairList = ExprPair { "," ExprPair } .
-ExprPair = Expression ":" Expression .
+CompositeLit  = LiteralType "(" [ ( ExpressionList | ExprPairList ) [ "," ] ] ")" .
+LiteralType   = StructType | ArrayType | "[" "..." "]" ElementType |
+                SliceType | MapType | TypeName .
+ExprPairList  = ExprPair { "," ExprPair } .
+ExprPair      = Expression ":" Expression .
 
-The LiteralType must be an struct, array, slice, or map type. +

+The LiteralType must be a struct, array, slice, or map type. +TODO: then why doesn't the grammar say that? The types of the expressions must match the respective field, element, and key types of the LiteralType; there is no automatic type conversion. -Composite literals are values of the type specified by LiteralType; that is -a new value is created every time the literal is evaluated. To get -a pointer to the literal, the address operator "&" must be used. -

Given +

 type Rat struct { num, den int }
 type Num struct { r Rat; f float; s string }
 
-one can write +

+one may write +

 pi := Num(Rat(22, 7), 3.14159, "pi");
 
+

The length of an array literal is the length specified in the LiteralType. If fewer elements than the length are provided in the literal, the missing elements are set to the zero value for the array element type. -It is an error to provide more elements than specified in LiteralType. The -notation "..." may be used in place of the length expression to denote a -length equal to the number of elements in the literal. +It is an error to provide more elements than specified in the type. The +notation ... specifies an array length equal +to the number of elements in the literal. +

 buffer := [10]string();               // len(buffer) == 10
 primes := [6]int(2, 3, 5, 7, 9, 11);  // len(primes) == 6
-days := [...]string("sat", "sun");    // len(days) == 2
+days := [...]string("Sat", "Sun");    // len(days) == 2
 
-A slice literal is a slice describing the entire underlying array literal. +

+A slice literal describes the entire underlying array literal. Thus, the length and capacity of a slice literal is the number of elements -provided in the literal. A slice literal of the form +(of the array) provided in the literal. A slice literal has the form +

 []T(x1, x2, ... xn)
 
-is essentially a shortcut for a slice operation applied to an array literal: +

+and is a shortcut for a slice operation applied to an array literal: +

 [n]T(x1, x2, ... xn)[0 : n]
 
-Map literals are similar except the elements of the expression list are +

+In map literals only, the list contains key-value pairs separated by a colon: +

 m := map[string]int("good": 0, "bad": 1, "indifferent": 7);
 
- -TODO: Consider adding helper syntax for nested composites -(avoids repeating types but complicates the spec needlessly.) - - -

Function literals

-A function literal represents an anonymous function. It consists of a -specification of the function type and the function body. The parameter -and result types of the function type must all be complete types (§Types). +

+A function literal represents an anonymous function. +It consists of a specification of the function type and a function body. +

-FunctionLit = "func" Signature Block .
-Block = "{" [ StatementList ] "}" .
+FunctionLit   = "func" Signature Block .
+Block         = "{" [ StatementList ] "}" .
 
-The type of a function literal is the function type specified. -
-func (a, b int, z float) bool { return a*b < int(z); }
+func (a, b int, z float) bool { return a*b < int(z) }
 
-A function literal can be assigned to a variable of the -corresponding function type, or invoked directly. +

+A function literal can be assigned to a variable or invoked directly. +

-f := func(x, y int) int { return x + y; }
-func(ch chan int) { ch <- ACK; } (reply_chan)
+f := func(x, y int) int { return x + y }
+func(ch chan int) { ch <- ACK } (reply_chan)
 
-Function literals are "closures": they may refer to variables +

+Function literals are closures: they may refer to variables defined in a surrounding function. Those variables are then shared between the surrounding function and the function literal, and they survive as long -as they are accessible in any way. +as they are accessible. +

Primary expressions

@@ -1948,11 +1973,11 @@ PrimaryExpr = PrimaryExpr TypeGuard | PrimaryExpr Call . -Selector = "." identifier . -Index = "[" Expression "]" . -Slice = "[" Expression ":" Expression "]" . -TypeGuard = "." "(" Type ")" . -Call = "(" [ ExpressionList ] ")" . +Selector = "." identifier . +Index = "[" Expression "]" . +Slice = "[" Expression ":" Expression "]" . +TypeGuard = "." "(" Type ")" . +Call = "(" [ ExpressionList ] ")" . @@ -1972,49 +1997,74 @@ f.p[i].x()

Selectors

+

A primary expression of the form +

 x.f
 
-denotes the field or method f of the value denoted by x (or of *x if -x is of pointer type). The identifier f is called the (field or method) -``selector''.

-A selector f may denote a field f declared in a type T, or it may refer -to a field f declared in a nested anonymous field of T. Analogously, -f may denote a method f of T, or it may refer to a method f of the type -of a nested anonymous field of T. The number of anonymous fields traversed -to get to the field or method is called its ``depth'' in T. +denotes the field or method f of the value denoted by x +(or of *x if +x is of pointer type). The identifier f +is called the (field or method) +selector. +The type of the expression is the type of f. +

-More precisely, the depth of a field or method f declared in T is zero. -The depth of a field or method f declared anywhere inside -an anonymous field A declared in T is the depth of f in A plus one. +A selector f may denote a field or method f of +a type T, or it may refer +to a field or method f of a nested anonymous field of +T. +The number of anonymous fields traversed +to reach f is called its depth in T. +The depth of a field or method f +declared in T is zero. +The depth of a field or method f declared in +an anonymous field A in T is the +depth of f in A plus one. +

The following rules apply to selectors: -

-1) For a value x of type T or *T where T is not an interface type, -x.f denotes the field or method at the shallowest depth in T where there -is such an f. The type of x.f is the type of the field or method f. -If there is not exactly one f with shallowest depth, the selector +

+
    +
  1. +For a value x of type T or *T +where T is not an interface type, +x.f denotes the field or method at the shallowest depth +in T where there +is such an f. +If there is not exactly one f with shallowest depth, the selector expression is illegal. +
  2. +
  3. +For a variable x of type I or *I +where I is an interface type, +x.f denotes the actual method with name f of the value assigned +to x if there is such a method. +If no value or nil was assigned to x, x.f is illegal. +
  4. +
  5. +In all other cases, x.f is illegal. +

-2) For a variable x of type I or *I where I is an interface type, -x.f denotes the actual method with name f of the value assigned -to x if there is such a method. The type of x.f is the type -of the method f. If no value or nil was assigned to x, x.f is illegal. +Selectors automatically dereference pointers as necessary. +If x is of pointer type, x.y +is shorthand for (*x).y; if y +is also of pointer type, x.y.z is shorthand +for (*(*x).y).z, and so on. +If *x is of pointer type, dereferencing +must be explicit; +only one level of automatic dereferencing is provided. +For an x of type T containing an +anonymous field declared as *A, +x.f is a shortcut for (*x.A).f. +

-3) In all other cases, x.f is illegal. -

-Thus, selectors automatically dereference pointers as necessary. For instance, -for an x of type *T where T declares an f, x.f is a shortcut for (*x).f. -Furthermore, for an x of type T containing an anonymous field A declared as *A -inside T, and where A contains a field f, x.f is a shortcut for (*x.A).f -(assuming that the selector is legal in the first place). -

-The following examples illustrate selector use in more detail. Given the -declarations: +For example, given the declarations: +

 type T0 struct {
@@ -2040,7 +2090,9 @@ func (recv *T2) M2()
 var p *T2;  // with p != nil and p.T1 != nil
 
-one can write: +

+one may write: +

 p.z         // (*p).z
@@ -2060,250 +2112,275 @@ TODO: Specify what happens to receivers.
 
 

Indexes

+

A primary expression of the form +

 a[x]
 

-denotes the array or map element x. The value x is called the -``array index'' or ``map key'', respectively. The following +denotes the array or map element of a indexed by x. +The value x is called the +array index or map key, respectively. The following rules apply:

-For a of type A or *A where A is an array type (§Array types): +For a of type A or *A +where A is an array type (§Array types):

-For a of type *M, where M is a map type (§Map types): +For a of type M or *M +where M is a map type (§Map types):

-Otherwise a[x] is illegal.

- -TODO: Need to expand map rules for assignments of the form v, ok = m[k]. - +Otherwise a[x] is illegal. If the index or key is out of range evaluating +an otherwise legal index expression, a run-time exception occurs. +

+

+However, if an index expression on a map a of type map[K] V +is used in an assignment of one of the special forms +

+ +
+r, ok = a[x]
+r, ok := a[x]
+
+ +

+the result of the index expression is a pair of values with types +(K, bool). +If the key is present in the map, +the expression returns the pair (a[x], true); +otherwise it returns (Z, false) where Z is +the zero value for V (§The zero value). +No run-time exception occurs in this case. +The index expression in this construct thus acts like a function call +returning a value and a boolean indicating success. (§Assignments) +

+ +

+Similarly, if an assignment to a map has the special form +

+ +
+a[x] = r, ok
+
+ +

+and boolean ok has the value false, +the entry for key x is deleted from the map; if +ok is true, the construct acts like +a regular assignment to an element of the map. +

Slices

+

Strings, arrays, and slices can be sliced to construct substrings or descriptors of subarrays. The index expressions in the slice select which elements appear in the result. The result has indexes starting at 0 and length equal to the -difference in the index values in the slice. After slicing the array "a" +difference in the index values in the slice. After slicing the array a +

 a := [4]int(1, 2, 3, 4);
 s := a[1:3];
 
-the slice "s" has type "[]int", length 2, and elements +

+the slice s has type []int, length 2, and elements +

 s[0] == 2
 s[1] == 3
 
+

The slice length must be non-negative. For arrays or strings, the index values in the slice must be in bounds for the original array or string; for slices, the index values must be between 0 and the capacity of the slice.

-If the sliced operand is a string, the result of the slice operation is another +If the sliced operand is a string, the result of the slice operation is another, new string (§String types). If the sliced operand is an array or slice, the result of the slice operation is a slice (§Slice types). +

Type guards

-For an expression "x" and a type "T", the primary expression +

+For an expression x and a type T, the primary expression +

 x.(T)
 
-asserts that the value stored in "x" is an element of type "T" (§Types). -The notation ".(T)" is called a ``type guard'', and "x.(T)" is called -a ``guarded expression''. The type of "x" must be an interface type.

-More precisely, if "T" is not an interface type, the expression asserts -that the dynamic type of "x" is identical to the type "T" (§Types). -If "T" is an interface type, the expression asserts that the dynamic type -of T implements the interface "T" (§Interface types). Because it can be -verified statically, a type guard in which the static type of "x" implements -the interface "T" is illegal. The type guard is said to succeed if the -assertion holds. +asserts that the value stored in x is of type T. +The notation .(T) is called a type guard, and x.(T) is called +a guarded expression. The type of x must be an interface type. +

+

+More precisely, if T is not an interface type, the type guard asserts +that the dynamic type of x is identical to the type T +(§Type equality and identity). +If T is an interface type, the type guard asserts that the dynamic type +of T implements the interface T (§Interface types). +The type guard is said to succeed if the assertion holds. +TODO: gri wants an error if x is already of type T. +

If the type guard succeeds, the value of the guarded expression is the value -stored in "x" and its type is "T". If the type guard fails, a run-time -exception occurs. In other words, even though the dynamic type of "x" -is only known at run-time, the type of the guarded expression "x.(T)" is -known to be "T" in a correct program. +stored in x and its type is T. If the type guard fails, a run-time +exception occurs. In other words, even though the dynamic type of x +is known only at run-time, the type of the guarded expression x.(T) is +known to be T in a correct program. +

-As a special form, if a guarded expression is used in an assignment +If a guarded expression is used in an assignment of one of the special forms, +

 v, ok = x.(T)
 v, ok := x.(T)
 
-the result of the guarded expression is a pair of values with types "(T, bool)". -If the type guard succeeds, the expression returns the pair "(x.(T), true)"; -that is, the value stored in "x" (of type "T") is assigned to "v", and "ok" -is set to true. If the type guard fails, the value in "v" is set to the zero -value for the type of "v" (§The zero value), and "ok" is -set to false. No run-time exception occurs in this case.

- -TODO add examples - +the result of the guarded expression is a pair of values with types (T, bool). +If the type guard succeeds, the expression returns the pair (x.(T), true); +otherwise, the expression returns (Z, false) where Z +is the zero value for type T (§The zero value). +No run-time exception occurs in this case. +The type guard in this construct thus acts like a function call +returning a value and a boolean indicating success. (§Assignments) +

Calls

- -TODO: This needs to be expanded and cleaned up. - - -Given a function or a function variable p, one writes - -
-p()
-
- -to call the function.

-A method is called using the notation +Given a function or a function variable f of function type +F, the expression +

-receiver.method()
+f(a, b, c)
 
-where receiver is a value of the receiver type of the method.

-For instance, given a *Point variable pt, one may call +calls the function with arguments a, b, c. +The arguments must be assignment compatible with the parameters of +F and are evaluated before the function is called. +The type of the expression is the result type +of F. +A method invocation is similar but the method itself +is specified as a selector upon a value of the receiver type for +the method. +

-pt.Scale(3.5)
+Atan2(x, y)    // function call
+var pt *Point;
+pt.Scale(3.5)  // method call with receiver pt
 
-The type of a method is the type of a function with the receiver as first -argument. For instance, the method "Scale" has type +

+If the receiver type of the method is declared as a pointer of type *T, +the actual receiver may be a value of type T; +in such cases method invocation implicitly takes the +receiver's address: +

-(p *Point, factor float)
+var p Point;
+p.Scale(3.5)
 
-However, a function declared this way is not a method.

There is no distinct method type and there are no method literals. +

+

Passing arguments to ... parameters

-

Parameter passing

- - -TODO expand this section (right now only "..." parameters are covered). - - -Inside a function, the type of the "..." parameter is the empty interface -"interface {}". The dynamic type of the parameter - that is, the type of -the value stored in the parameter - is of the form (in pseudo- -notation) - -
-*struct {
-	arg(0) typeof(arg(0));
-	arg(1) typeof(arg(1));
-	arg(2) typeof(arg(2));
-	...
-	arg(n-1) typeof(arg(n-1));
-}
-
- -where the "arg(i)"'s correspond to the actual arguments passed in place -of the "..." parameter (the parameter and type names are for illustration -only). Reflection code may be used to access the struct value and its fields. -Thus, arguments provided in place of a "..." parameter are wrapped into -a corresponding struct, and a pointer to the struct is passed to the -function instead of the actual arguments. - -For instance, consider the function - -
-func f(x int, s string, f_extra ...)
-
- -and the call - -
-f(42, "foo", 3.14, true, []int(1, 2, 3))
-
- -Upon invocation, the parameters "3.14", "true", and "[]int(1, 2, 3)" -are wrapped into a struct and the pointer to the struct is passed to f. -In f the type of parameter "f_extra" is "interface{}". -The dynamic type of "f_extra" is the type of the value assigned -to it upon invocation (the field names "arg0", "arg1", "arg2" are made -up for illustration only, they are not accessible via reflection): - -
-*struct {
-	arg0 float;
-	arg1 bool;
-	arg2 []int;
-}
-
- -The values of the fields "arg0", "arg1", and "arg2" are "3.14", "true", -and "[]int(1, 2, 3)".

-As a special case, if a function passes a "..." parameter as the argument -for a "..." parameter of a function, the parameter is not wrapped again into -a struct. Instead it is passed along unchanged. For instance, the function -f may call a function g with declaration +When a function f has a ... parameter, +it is always the last formal parameter. Within calls to f, +the arguments before the ... are treated normally. +After those, an arbitrary number (including zero) of trailing +arguments may appear in the call and are bound to the ... +parameter. +

+

+Within f, the ... parameter has static +type interface{} (the empty interface). For each call, +its dynamic type is a structure whose sequential fields are the +trailing arguments of the call. That is, the actual arguments +provided for a ... parameter are wrapped into a struct +that is passed to the function instead of the actual arguments. +Using the reflection library (TODO: reference), f may +unpack the elements of the dynamic type to recover the actual +arguments. +

+ +

+Given the function and call +

-func g(x int, g_extra ...)
+func Fprintf(f io.Write, format string, args ...)
+Fprintf(os.Stdout, "%s %d", "hello", 23);
 
-as +

+Within Fprintf, the dynamic type of args for this +call will be, schematically, + struct { string; int }. +

-
-g(x, f_extra);
-
- -Inside g, the value stored in g_extra is the same as the value stored -in f_extra. +

+As a special case, if a function passes its own ... parameter as the argument +for a ... in a call to another function with a ... parameter, +the parameter is not wrapped again but passed directly. In short, a formal ... +parameter is passed unchanged as an actual ... parameter.

Operators

+

Operators combine operands into expressions. +

 Expression = UnaryExpr | Expression binaryOp UnaryExpr .
-UnaryExpr = PrimaryExpr | unary_op UnaryExpr .
+UnaryExpr  = PrimaryExpr | unary_op UnaryExpr .
 
-binary_op = log_op | com_op | rel_op | add_op | mul_op .
-log_op = "||" | "&&" .
-com_op = "<-" .
-rel_op = "==" | "!=" | "<" | "<=" | ">" | ">=" .
-add_op = "+" | "-" | "|" | "^" .
-mul_op = "*" | "/" | "%" | "<<" | ">>" | "&" .
+binary_op  = log_op | com_op | rel_op | add_op | mul_op .
+log_op     = "||" | "&&" .
+com_op     = "<-" .
+rel_op     = "==" | "!=" | "<" | "<=" | ">" | ">=" .
+add_op     = "+" | "-" | "|" | "^" .
+mul_op     = "*" | "/" | "%" | "<<" | ">>" | "&" .
 
-unary_op = "+" | "-" | "!" | "^" | "*" | "&" | "<-" .
+unary_op   = "+" | "-" | "!" | "^" | "*" | "&" | "<-" .
 

@@ -2312,29 +2389,36 @@ The operand types in binary operations must be equal, with the following excepti

-Unary operators have the highest precedence. They are evaluated from -right to left. Note that "++" and "--" are outside the unary operator -hierarchy (they are statements) and they apply to the operand on the left. -Specifically, "*p++" means "(*p)++" in Go (as opposed to "*(p++)" in C).

-There are six precedence levels for binary operators: -multiplication operators bind strongest, followed by addition +Unary operators have the highest precedence. They are evaluated from +right to left. As the ++ and -- operators form +statements, not expressions, they fall +outside the unary operator hierarchy and apply +to the operand on the left. +As a consequence, statement *p++ is the same as (*p)++. +

+There are six precedence levels for binary operators. +Multiplication operators bind strongest, followed by addition operators, comparison operators, communication operators, -"&&" (logical and), and finally "||" (logical or) with the -lowest precedence: +&& (logical and), and finally || (logical or): +

 Precedence    Operator
@@ -2346,10 +2430,13 @@ Precedence    Operator
     1             ||
 
-Binary operators of the same precedence associate from left to right. -For instance, "x / y / z" stands for "(x / y) / z".

-Examples +Binary operators of the same precedence associate from left to right. +For instance, x / y / z is the same as (x / y) / z. +

+

+Examples: +

 +x
@@ -2364,12 +2451,14 @@ x == y + 1 && <-chan_ptr > 0
 

Arithmetic operators

Arithmetic operators apply to numeric types and yield a result of the same -type as the first operand. The four standard arithmetic operators ("+", "-", -"*", "/") apply to both integer and floating point types, while "+" also applies -to strings and arrays; all other arithmetic operators apply to integer types only. +type as the first operand. The four standard arithmetic operators (+, +-, *, /) apply both to integer and +floating point types, while + applies also +to strings; all other arithmetic operators apply to integers only. +

-+    sum             integers, floats, strings, arrays
++    sum             integers, floats, strings
 -    difference      integers, floats
 *    product         integers, floats
 /    quotient        integers, floats
@@ -2383,27 +2472,31 @@ to strings and arrays; all other arithmetic operators apply to integer types onl
 >>   right shift     integer >> unsigned integer
 
-Strings can be concatenated using the "+" operator (or the "+=" assignment): +

+Strings can be concatenated using the + operator +or the += assignment operator: +

-s := "hi" + string(c)
+s := "hi" + string(c);
+s += " and good bye";
 
-String addition creates a new string by copying the elements.

-For integer values, "/" and "%" satisfy the following relationship: +String addition creates a new string by concatenating the operands. +

+

+For integer values, / and % satisfy the following relationship: +

 (a / b) * b + a % b == a
 
-and - -
-(a / b) is "truncated towards zero".
-
- +

+with (a / b) truncated towards zero. Examples: +

  x     y     x / y     x % y
@@ -2413,9 +2506,11 @@ Examples:
 -5    -3       1        -2
 
-Note that if the dividend is positive and the divisor is a constant power of 2, +

+If the dividend is positive and the divisor is a constant power of 2, the division may be replaced by a left shift, and computing the remainder may be replaced by a bitwise "and" operation: +

  x     x / 4     x % 4     x >> 2     x & 3
@@ -2423,16 +2518,23 @@ be replaced by a bitwise "and" operation:
 -11     -2        -3        -3          1
 
+

The shift operators shift the left operand by the shift count specified by the right operand. They implement arithmetic shifts if the left operand is a signed -integer, and logical shifts if it is an unsigned integer. The shift count must -be an unsigned integer. There is no upper limit on the shift count. It is -as if the left operand is shifted "n" times by 1 for a shift count of "n". -Specifically, "x << 1" is the same as "x*2"; and "x >> 1" is the same as -"x/2 truncated towards negative infinity". +integer and logical shifts if it is an unsigned integer. The shift count must +be an unsigned integer. There is no upper limit on the shift count. Shifts behave +as if the left operand is shifted n times by 1 for a shift +count of n. +As a result, x << 1 is the same as x*2 +and x >> 1 is the same as +x/2 truncated towards negative infinity. +

-For integer operands, the unary operators "+", "-", and "^" are defined as +

+For integer operands, the unary operators ++, -, and ^ are defined as follows: +

 +x                          is 0 + x
@@ -2443,17 +2545,23 @@ follows:
 
 

Integer overflow

-For unsigned integer values, the operations "+", "-", "*", and "<<" are -computed modulo 2^n, where n is the bit width of the unsigned integer type +

+For unsigned integer values, the operations +, +-, *, and << are +computed modulo 2n, where n is the bit width of +the unsigned integer's type (§Arithmetic types). Loosely speaking, these unsigned integer operations discard high bits upon overflow, and programs may rely on ``wrap around''. +

-For signed integers, the operations "+", "-", "*", and "<<" may legally +For signed integers, the operations +, +-, *, and << may legally overflow and the resulting value exists and is deterministically defined by the signed integer representation, the operation, and its operands. -No exception is raised as a result of overflow. As a consequence, a +No exception is raised as a result of overflow. A compiler may not optimize code under the assumption that overflow does -not occur. For instance, it may not assume that "x < x + 1" is always true. +not occur. For instance, it may not assume that x < x + 1 is always true. +

Comparison operators

@@ -2491,8 +2599,10 @@ section on §Comparison compatibility.

Logical operators

+

Logical operators apply to boolean operands and yield a boolean result. The right operand is evaluated conditionally. +

 &&    conditional and    p && q  is  "if p then q else false"
@@ -2503,6 +2613,9 @@ The right operand is evaluated conditionally.
 
 

Address operators

+ + +

TODO: Need to talk about unary "*", clean up section below.

TODO: This text needs to be cleaned up and go elsewhere, there are no address @@ -2598,42 +2711,34 @@ of a result parameter (e.g.: func f() (x int, p *int) { return 2, &x }).

Communication operators

-The syntax presented above covers communication operations. This -section describes their form and function.

-Here the term "channel" means "variable of type chan". +The term channel means "variable of channel type" (§Channel types). +

-The built-in function "make" makes a new channel value: - -

-ch := make(chan int)
-
- -An optional argument to "make()" specifies a buffer size for an -asynchronous channel; if absent or zero, the channel is synchronous: - -
-sync_chan := make(chan int)
-buffered_chan := make(chan int, 10)
-
- The send operation uses the binary operator "<-", which operates on a channel and a value (expression): +

 ch <- 3
 
-In this form, the send operation is an (expression) statement that -sends the value on the channel. Both the channel and the expression -are evaluated before communication begins. Communication blocks -until the send can proceed, at which point the value is transmitted -on the channel. +

+The send operation sends the value on the channel. Both the channel +and the expression are evaluated before communication begins. +Communication blocks until the send can proceed, at which point the +value is transmitted on the channel. A send can proceed if the +channel is asynchronous and there is room in its buffer or the +channel is synchronous and a receiver is ready. +

If the send operation appears in an expression context, the value of the expression is a boolean and the operation is non-blocking. The value of the boolean reports true if the communication succeeded, -false if it did not. These two examples are equivalent: +false if it did not. (The channel and +the expression to be sent are evaluated regardless.) +These two examples are equivalent: +

 ok := ch <- 3;
@@ -2642,49 +2747,58 @@ if ok { print("sent") } else { print("not sent") }
 if ch <- 3 { print("sent") } else { print("not sent") }
 
+

In other words, if the program tests the value of a send operation, the send is non-blocking and the value of the expression is the success of the operation. If the program does not test the value, the operation blocks until it succeeds. -

- -TODO: Adjust the above depending on how we rule on the ok semantics. -For instance, does the sent expression get evaluated if ok is false? - +

The receive operation uses the prefix unary operator "<-". -The value of the expression is the value received: +The value of the expression is the value received, whose type +is the element type of the channel. +

 <-ch
 
+

The expression blocks until a value is available, which then can -be assigned to a variable or used like any other expression: +be assigned to a variable or used like any other expression. +If the receive expression does not save the value, the value is +discarded. +

 v1 := <-ch
 v2 = <-ch
 f(<-ch)
-
- -If the receive expression does not save the value, the value is -discarded: - -
 <-strobe  // wait until clock pulse
 
+

If a receive expression is used in a tuple assignment of the form +

 x, ok = <-ch;  // or: x, ok := <-ch
 
-the receive operation becomes non-blocking, and the boolean variable -"ok" will be set to "true" if the receive operation succeeded, and set -to "false" otherwise. +

+the receive operation becomes non-blocking. +If the operation can proceeed, the boolean variable +ok will be set to true +and the value stored in x; otherwise +ok is set +to false and x is set to the +zero value for its type (§The zero value). +

+

+TODO: Probably in a separate section, communication semantices +need to be presented regarding send, receive, select, and goroutines. +

Constant expressions

@@ -2696,8 +2810,8 @@ and len applied to an array. In practice, constant expressions are those that can be evaluated at compile time.

The type of a constant expression is determined by the type of its -elements. If it contains only numeric literals, its type is ``ideal -integer'' or ``ideal float'' (§Ideal number). Whether it is an +elements. If it contains only numeric literals, its type is ideal +integer or ideal float (§Ideal number). Whether it is an integer or float depends on whether the value can be represented precisely as an integer (123 vs. 1.23). The nature of the arithmetic operations within the expression depends, elementwise, on the values; @@ -2729,12 +2843,16 @@ const Four int8 = Huge >> 98;

A constant expression may appear in any context, such as assignment to a variable of any numeric type, as long as the value of the -expression can be represented accurately in that context. For -instance, 3 can be assigned to any integer variable but also to any -floating point variable, while 1e12 can be assigned to a -float32, float64, or even int64. +expression can be represented accurately in that context. It is erroneous to assign a value with a non-zero fractional part -to an integer, or if the assignment would overflow or underflow. +to an integer, or if the assignment would overflow or underflow, +or in general if the value cannot be represented by the type of +the variable. +For +instance, 3 can be assigned to any integer variable but also to any +floating point variable, while -1e12 can be assigned to a +float32, float64, or even int64 +but not uint64 or string.


@@ -3392,30 +3510,27 @@ for i := 0; i <= 3; i++ {

Length and capacity

-Call      Argument type        Result
+Call       Argument type       Result
 
 len(s)    string, *string      string length (in bytes)
-		  [n]T, *[n]T          array length (== n)
-		  []T, *[]T            slice length
-		  map[K]T, *map[K]T    map length
-		  chan T               number of elements in channel buffer
+          [n]T, *[n]T          array length (== n)
+          []T, *[]T            slice length
+          map[K]T, *map[K]T    map length
+          chan T               number of elements in channel buffer
 
 cap(s)    []T, *[]T            capacity of s
-		  map[K]T, *map[K]T    capacity of s
-		  chan T               channel buffer capacity
+          map[K]T, *map[K]T    capacity of s
+          chan T               channel buffer capacity
 
- -TODO: confirm len() and cap() for channels - -

-The type of the result is always "int" and the implementation guarantees that -the result always fits into an "int". +The type of the result is always int and the +implementation guarantees that +the result always fits into an int.

The capacity of a slice or map is the number of elements for which there is -space allocated in the underlying array (for a slice) or map. For a slice "s", -at any time the following relationship holds: +space allocated in the underlying array (for a slice) or map. For a slice +s, at any time the following relationship holds:

 0 <= len(s) <= cap(s)
@@ -3430,9 +3545,9 @@ Conversions syntactically look like function calls of the form
 T(value)
 
-where "T" is the type name of an arithmetic type or string (§Basic types), -and "value" is the value of an expression which can be converted to a value -of result type "T". +where T is the type name of an arithmetic type or string (§Basic types), +and value is the value of an expression that can be converted to a value +of result type T.

The following conversion rules apply:

@@ -3452,27 +3567,32 @@ result. TODO: clarify?

3a) Converting an integer value yields a string containing the UTF-8 representation of the integer. +(TODO: this one could be done just as well by a library.) +

 string(0x65e5)  // "\u65e5"
 
+

3b) Converting an array of uint8s yields a string whose successive bytes are those of the array. (Recall byte is a synonym for uint8.) +

 string([]byte('h', 'e', 'l', 'l', 'o')) // "hello"
 
+

There is no linguistic mechanism to convert between pointers and integers. A library may be provided under restricted circumstances to acccess this conversion in low-level code. -

TODO: Do we allow interface/ptr conversions in this form or do they have to be written as type guards? (§Type guards) +

Allocation

@@ -3845,8 +3965,17 @@ The following minimal alignment properties are guaranteed:

Differences between this doc and implementation - TODO

-Current implementation accepts only ASCII digits for digits; doc says Unicode. -
+Implementation accepts only ASCII digits for digits; doc says Unicode. +
+Implementation does not allow p.x where p is the local package name. +
+Implementation does not honor the restriction on goto statements and targets (no intervening declarations). +
+cap() does not work on maps or chans. +
+len() does not work on chans. +
+Conversions work for any type; doc says only arithmetic types and strings.