Test balloon: Changed the spec to see the implications of changing the
syntax of function types and making them "reference types" like slice,
map, and chan. First step in Russ' proposal.
DELTA=111 (32 added, 15 deleted, 64 changed)
OCL=23669
CL=23964
diff --git a/doc/go_spec.txt b/doc/go_spec.txt
index 15a3512..2516942 100644
--- a/doc/go_spec.txt
+++ b/doc/go_spec.txt
@@ -3,7 +3,7 @@
Robert Griesemer, Rob Pike, Ken Thompson
-(January 27, 2009)
+(January 30, 2009)
----
@@ -1215,7 +1215,7 @@
StructType = "struct" [ "{" [ FieldDeclList ] "}" ] .
FieldDeclList = FieldDecl { ";" FieldDecl } [ ";" ] .
FieldDecl = (IdentifierList CompleteType | TypeName) [ Tag ] .
- Tag = string_lit .
+ Tag = StringLit .
// An empty struct.
struct {}
@@ -1225,7 +1225,7 @@
x, y int;
u float;
A *[]int;
- F *();
+ F func();
}
A struct may contain ``anonymous fields'', which are declared with a type
@@ -1326,9 +1326,10 @@
----
A function type denotes the set of all functions with the same parameter
-and result types.
+and result types, and the value "nil".
- FunctionType = "(" [ ParameterList ] ")" [ Result ] .
+ FunctionType = "func" Signature .
+ Signature = "(" [ ParameterList ] ")" [ Result ] .
ParameterList = ParameterDecl { "," ParameterDecl } .
ParameterDecl = [ IdentifierList ] ( Type | "..." ) .
Result = Type | "(" ParameterList ")" .
@@ -1345,22 +1346,32 @@
list immediately preceding "..." must contain only one identifier (the
name of the last parameter).
- ()
- (x int)
- () int
- (string, float, ...)
- (a, b int, z float) bool
- (a, b int, z float) (bool)
- (a, b int, z float, opt ...) (success bool)
- (int, int, float) (float, *[]int)
+ func ()
+ func (x int)
+ func () int
+ func (string, float, ...)
+ func (a, b int, z float) bool
+ func (a, b int, z float) (bool)
+ func (a, b int, z float, opt ...) (success bool)
+ func (int, int, float) (float, *[]int)
-A variable can hold only a pointer to a function, not a function value.
-In particular, v := func() {} creates a variable of type *(). To call the
-function referenced by v, one writes v(). It is illegal to dereference a
-function pointer.
+If the result type of a function is itself a function type, the result type
+must be parenthesized to resolve a parsing ambiguity:
-Assignment compatibility: A function pointer can be assigned to a function
-(pointer) variable only if both function types are equal.
+ func (n int) (func (p* T))
+
+Assignment compatibility: A function can be assigned to a function
+variable only if both function types are equal.
+
+Comparisons: A variable of function type can be compared against "nil" with the
+operators "==" and "!=" (§Comparison operators). The variable is
+"nil" only if "nil" is assigned explicitly to the variable (§Assignments), or
+if the variable has not been modified since creation (§Program initialization
+and execution).
+
+Two variables of equal function type can be tested for equality with the
+operators "==" and "!=" (§Comparison operators). The variables are equal
+if they refer to the same function.
Interface types
@@ -1372,7 +1383,7 @@
InterfaceType = "interface" [ "{" [ MethodSpecList ] "}" ] .
MethodSpecList = MethodSpec { ";" MethodSpec } [ ";" ] .
- MethodSpec = IdentifierList FunctionType .
+ MethodSpec = IdentifierList Signature .
// An interface specifying a basic File type.
interface {
@@ -1704,8 +1715,8 @@
T1 []string
T2 struct { a, b int };
T3 struct { a, c int };
- T4 *(int, float) *T0
- T5 *(x int, y float) *[]string
+ T4 func (int, float) *T0
+ T5 func (x int, y float) *[]string
)
these are some types that are equal
@@ -1759,7 +1770,8 @@
Operand = Literal | QualifiedIdent | "(" Expression ")" .
Literal = BasicLit | CompositeLit | FunctionLit .
- BasicLit = int_lit | float_lit | char_lit | string_lit .
+ BasicLit = int_lit | float_lit | char_lit | StringLit .
+ StringLit = string_lit { string_lit } .
Constants
@@ -1848,15 +1860,15 @@
specification of the function type and the function body. The parameter
and result types of the function type must all be complete types (§Types).
- FunctionLit = "func" FunctionType Block .
+ FunctionLit = "func" Signature Block .
Block = "{" [ StatementList ] "}" .
-The type of a function literal is a pointer to the function type.
+The type of a function literal is the function type specified.
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 pointer type, or invoked directly.
+corresponding function type, or invoked directly.
f := func(x, y int) int { return x + y; }
func(ch chan int) { ch <- ACK; } (reply_chan)
@@ -2073,7 +2085,9 @@
Calls
----
-Given a function pointer, one writes
+TODO: This needs to be expanded and cleaned up.
+
+Given a function or a function variable p, one writes
p()
@@ -2083,7 +2097,7 @@
receiver.method()
-where receiver is a value of the receive type of the method.
+where receiver is a value of the receiver type of the method.
For instance, given a *Point variable pt, one may call
@@ -2357,26 +2371,11 @@
TODO: Need to talk about unary "*", clean up section below.
-Given a function f, declared as
+TODO: This text needs to be cleaned up and go elsewhere, there are no address
+operators involved.
- func f(a int) int;
-
-taking the address of f with the expression
-
- &f
-
-creates a pointer to the function that may be stored in a value of type pointer
-to function:
-
- var fp *(a int) int = &f;
-
-The function pointer may be invoked with the usual syntax; no explicit
-indirection is required:
-
- fp(7)
-
-Methods are a form of function, and the address of a method has the type
-pointer to function. Consider the type T with method M:
+Methods are a form of function, and a method ``value'' has a function type.
+Consider the type T with method M:
type T struct {
a int;
@@ -2384,45 +2383,62 @@
func (tp *T) M(a int) int;
var t *T;
-To construct the address of method M, one writes
+To construct the value of method M, one writes
- &t.M
+ t.M
-using the variable t (not the type T). The expression is a pointer to a
-function, with type
+using the variable t (not the type T).
+TODO: It makes perfect sense to be able to say T.M (in fact, it makes more
+sense then t.M, since only the type T is needed to find the method M, i.e.,
+its address). TBD.
- *(t *T, a int) int
+The expression t.M is a function value with type
-and may be invoked only as a function, not a method:
+ func (t *T, a int) int
- var f *(t *T, a int) int;
- f = &t.M;
+and may be invoked only as a function, not as a method:
+
+ var f func (t *T, a int) int;
+ f = t.M;
x := f(t, 7);
-Note that one does not write t.f(7); taking the address of a method demotes
+Note that one does not write t.f(7); taking the value of a method demotes
it to a function.
-In general, given type T with method M and variable t of type *T,
+In general, given type T with method M and variable t of type T,
the method invocation
t.M(args)
is equivalent to the function call
- (&t.M)(t, args)
+ (t.M)(t, args)
-If T is an interface type, the expression &t.M does not determine which
+TODO: should probably describe the effect of (t.m) under §Expressions if t.m
+denotes a method: Effect is as described above, converts into function.
+
+If T is an interface type, the expression t.M does not determine which
underlying type's M is called until the point of the call itself. Thus given
T1 and T2, both implementing interface I with interface M, the sequence
var t1 *T1;
var t2 *T2;
var i I = t1;
- m := &i.M;
- m(t2);
+ m := i.M;
+ m(t2, 7);
will invoke t2.M() even though m was constructed with an expression involving
-t1.
+t1. Effectively, the value of m is a function literal
+
+ func (recv I, a int) {
+ recv.M(a);
+ }
+
+that is automatically created.
+
+TODO: Document implementation restriction: It is illegal to take the address
+of a result parameter (e.g.: func f() (x int, p *int) { return 2, &x }).
+(TBD: is it an implementation restriction or fact?)
Communication operators
@@ -2643,7 +2659,7 @@
the "if" branch is executed. Otherwise the "else" branch is executed if present.
If Condition is omitted, it is equivalent to true.
- IfStat = "if" [ [ Simplestat ] ";" ] [ Expression ] Block [ "else" Statement ] .
+ IfStat = "if" [ [ SimpleStat ] ";" ] [ Expression ] Block [ "else" Statement ] .
if x > 0 {
return true;
@@ -2666,7 +2682,7 @@
TODO: gri thinks that Statement needs to be changed as follows:
IfStat =
- "if" [ [ Simplestat ] ";" ] [ Expression ] Block
+ "if" [ [ SimpleStat ] ";" ] [ Expression ] Block
[ "else" ( IfStat | Block ) ] .
To facilitate the "if else if" code pattern, if the "else" branch is
@@ -2688,7 +2704,7 @@
Switches provide multi-way execution.
- SwitchStat = "switch" [ [ Simplestat ] ";" ] [ Expression ] "{" { CaseClause } "}" .
+ SwitchStat = "switch" [ [ SimpleStat ] ";" ] [ Expression ] "{" { CaseClause } "}" .
CaseClause = SwitchCase ":" [ StatementList ] .
SwitchCase = "case" ExpressionList | "default" .
@@ -3069,9 +3085,9 @@
A function declaration binds an identifier to a function.
Functions contain declarations and statements. They may be
recursive. Except for forward declarations (see below), the parameter
-and result types of the function type must all be complete types (§Type declarations).
+and result types of the signature must all be complete types (§Type declarations).
- FunctionDecl = "func" identifier FunctionType [ Block ] .
+ FunctionDecl = "func" identifier Signature [ Block ] .
func min(x int, y int) int {
if x < y {
@@ -3102,7 +3118,7 @@
receiver value is not needed inside the method, its identifier may be omitted
in the declaration.
- MethodDecl = "func" Receiver identifier FunctionType [ Block ] .
+ MethodDecl = "func" Receiver identifier Signature [ Block ] .
Receiver = "(" [ identifier ] [ "*" ] TypeName ")" .
All methods bound to a receiver base type must have the same receiver type:
@@ -3296,6 +3312,7 @@
ImportDecl = "import" ( ImportSpec | "(" [ ImportSpecList ] ")" ) .
ImportSpecList = ImportSpec { ";" ImportSpec } [ ";" ] .
ImportSpec = [ "." | PackageName ] PackageFileName .
+ PackageFileName = StringLit .
An import statement makes the exported top-level identifiers of the named
package file accessible to this package.