1
0
mirror of https://github.com/golang/go synced 2024-11-22 06:14:39 -07:00

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
This commit is contained in:
Robert Griesemer 2009-01-30 14:48:29 -08:00
parent 4a43198390
commit 2b9fe0ea24

View File

@ -3,7 +3,7 @@ The Go Programming Language Specification (DRAFT)
Robert Griesemer, Rob Pike, Ken Thompson Robert Griesemer, Rob Pike, Ken Thompson
(January 27, 2009) (January 30, 2009)
---- ----
@ -1215,7 +1215,7 @@ types (§Types).
StructType = "struct" [ "{" [ FieldDeclList ] "}" ] . StructType = "struct" [ "{" [ FieldDeclList ] "}" ] .
FieldDeclList = FieldDecl { ";" FieldDecl } [ ";" ] . FieldDeclList = FieldDecl { ";" FieldDecl } [ ";" ] .
FieldDecl = (IdentifierList CompleteType | TypeName) [ Tag ] . FieldDecl = (IdentifierList CompleteType | TypeName) [ Tag ] .
Tag = string_lit . Tag = StringLit .
// An empty struct. // An empty struct.
struct {} struct {}
@ -1225,7 +1225,7 @@ types (§Types).
x, y int; x, y int;
u float; u float;
A *[]int; A *[]int;
F *(); F func();
} }
A struct may contain ``anonymous fields'', which are declared with a type A struct may contain ``anonymous fields'', which are declared with a type
@ -1326,9 +1326,10 @@ Function types
---- ----
A function type denotes the set of all functions with the same parameter 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 } . ParameterList = ParameterDecl { "," ParameterDecl } .
ParameterDecl = [ IdentifierList ] ( Type | "..." ) . ParameterDecl = [ IdentifierList ] ( Type | "..." ) .
Result = Type | "(" ParameterList ")" . Result = Type | "(" ParameterList ")" .
@ -1345,22 +1346,32 @@ no additional arguments). If the parameters are named, the identifier
list immediately preceding "..." must contain only one identifier (the list immediately preceding "..." must contain only one identifier (the
name of the last parameter). name of the last parameter).
() func ()
(x int) func (x int)
() int func () int
(string, float, ...) func (string, float, ...)
(a, b int, z float) bool func (a, b int, z float) bool
(a, b int, z float) (bool) func (a, b int, z float) (bool)
(a, b int, z float, opt ...) (success bool) func (a, b int, z float, opt ...) (success bool)
(int, int, float) (float, *[]int) func (int, int, float) (float, *[]int)
A variable can hold only a pointer to a function, not a function value. If the result type of a function is itself a function type, the result type
In particular, v := func() {} creates a variable of type *(). To call the must be parenthesized to resolve a parsing ambiguity:
function referenced by v, one writes v(). It is illegal to dereference a
function pointer.
Assignment compatibility: A function pointer can be assigned to a function func (n int) (func (p* T))
(pointer) variable only if both function types are equal.
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 Interface types
@ -1372,7 +1383,7 @@ the set of methods specified by the interface type, and the value "nil".
InterfaceType = "interface" [ "{" [ MethodSpecList ] "}" ] . InterfaceType = "interface" [ "{" [ MethodSpecList ] "}" ] .
MethodSpecList = MethodSpec { ";" MethodSpec } [ ";" ] . MethodSpecList = MethodSpec { ";" MethodSpec } [ ";" ] .
MethodSpec = IdentifierList FunctionType . MethodSpec = IdentifierList Signature .
// An interface specifying a basic File type. // An interface specifying a basic File type.
interface { interface {
@ -1704,8 +1715,8 @@ For instance, given the declarations
T1 []string T1 []string
T2 struct { a, b int }; T2 struct { a, b int };
T3 struct { a, c int }; T3 struct { a, c int };
T4 *(int, float) *T0 T4 func (int, float) *T0
T5 *(x int, y float) *[]string T5 func (x int, y float) *[]string
) )
these are some types that are equal these are some types that are equal
@ -1759,7 +1770,8 @@ Operands denote the elementary values in an expression.
Operand = Literal | QualifiedIdent | "(" Expression ")" . Operand = Literal | QualifiedIdent | "(" Expression ")" .
Literal = BasicLit | CompositeLit | FunctionLit . 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 Constants
@ -1848,15 +1860,15 @@ A function literal represents an anonymous function. It consists of a
specification of the function type and the function body. The parameter specification of the function type and the function body. The parameter
and result types of the function type must all be complete types (§Types). and result types of the function type must all be complete types (§Types).
FunctionLit = "func" FunctionType Block . FunctionLit = "func" Signature Block .
Block = "{" [ StatementList ] "}" . 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); } func (a, b int, z float) bool { return a*b < int(z); }
A function literal can be assigned to a variable of the 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; } f := func(x, y int) int { return x + y; }
func(ch chan int) { ch <- ACK; } (reply_chan) func(ch chan int) { ch <- ACK; } (reply_chan)
@ -2073,7 +2085,9 @@ TODO add examples
Calls 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() p()
@ -2083,7 +2097,7 @@ A method is called using the notation
receiver.method() 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 For instance, given a *Point variable pt, one may call
@ -2357,26 +2371,11 @@ Address operators
TODO: Need to talk about unary "*", clean up section below. 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; Methods are a form of function, and a method ``value'' has a function type.
Consider the type T with method M:
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:
type T struct { type T struct {
a int; a int;
@ -2384,45 +2383,62 @@ pointer to function. Consider the type T with method M:
func (tp *T) M(a int) int; func (tp *T) M(a int) int;
var t *T; 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 using the variable t (not the type T).
function, with type 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; and may be invoked only as a function, not as a method:
f = &t.M;
var f func (t *T, a int) int;
f = t.M;
x := f(t, 7); 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. 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 the method invocation
t.M(args) t.M(args)
is equivalent to the function call 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 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 T1 and T2, both implementing interface I with interface M, the sequence
var t1 *T1; var t1 *T1;
var t2 *T2; var t2 *T2;
var i I = t1; var i I = t1;
m := &i.M; m := i.M;
m(t2); m(t2, 7);
will invoke t2.M() even though m was constructed with an expression involving 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 Communication operators
@ -2643,7 +2659,7 @@ and the "else" branch. If Expression evaluates to true,
the "if" branch is executed. Otherwise the "else" branch is executed if present. the "if" branch is executed. Otherwise the "else" branch is executed if present.
If Condition is omitted, it is equivalent to true. 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 { if x > 0 {
return true; return true;
@ -2666,7 +2682,7 @@ the variable is initialized once before the statement is entered.
TODO: gri thinks that Statement needs to be changed as follows: TODO: gri thinks that Statement needs to be changed as follows:
IfStat = IfStat =
"if" [ [ Simplestat ] ";" ] [ Expression ] Block "if" [ [ SimpleStat ] ";" ] [ Expression ] Block
[ "else" ( IfStat | Block ) ] . [ "else" ( IfStat | Block ) ] .
To facilitate the "if else if" code pattern, if the "else" branch is To facilitate the "if else if" code pattern, if the "else" branch is
@ -2688,7 +2704,7 @@ Switch statements
Switches provide multi-way execution. Switches provide multi-way execution.
SwitchStat = "switch" [ [ Simplestat ] ";" ] [ Expression ] "{" { CaseClause } "}" . SwitchStat = "switch" [ [ SimpleStat ] ";" ] [ Expression ] "{" { CaseClause } "}" .
CaseClause = SwitchCase ":" [ StatementList ] . CaseClause = SwitchCase ":" [ StatementList ] .
SwitchCase = "case" ExpressionList | "default" . SwitchCase = "case" ExpressionList | "default" .
@ -3069,9 +3085,9 @@ Function declarations
A function declaration binds an identifier to a function. A function declaration binds an identifier to a function.
Functions contain declarations and statements. They may be Functions contain declarations and statements. They may be
recursive. Except for forward declarations (see below), the parameter 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 { func min(x int, y int) int {
if x < y { if x < y {
@ -3102,7 +3118,7 @@ it is declared within the scope of that type (§Type declarations). If the
receiver value is not needed inside the method, its identifier may be omitted receiver value is not needed inside the method, its identifier may be omitted
in the declaration. in the declaration.
MethodDecl = "func" Receiver identifier FunctionType [ Block ] . MethodDecl = "func" Receiver identifier Signature [ Block ] .
Receiver = "(" [ identifier ] [ "*" ] TypeName ")" . Receiver = "(" [ identifier ] [ "*" ] TypeName ")" .
All methods bound to a receiver base type must have the same receiver type: All methods bound to a receiver base type must have the same receiver type:
@ -3296,6 +3312,7 @@ through an import declaration:
ImportDecl = "import" ( ImportSpec | "(" [ ImportSpecList ] ")" ) . ImportDecl = "import" ( ImportSpec | "(" [ ImportSpecList ] ")" ) .
ImportSpecList = ImportSpec { ";" ImportSpec } [ ";" ] . ImportSpecList = ImportSpec { ";" ImportSpec } [ ";" ] .
ImportSpec = [ "." | PackageName ] PackageFileName . ImportSpec = [ "." | PackageName ] PackageFileName .
PackageFileName = StringLit .
An import statement makes the exported top-level identifiers of the named An import statement makes the exported top-level identifiers of the named
package file accessible to this package. package file accessible to this package.