Commit 2b9fe0ea authored by Robert Griesemer's avatar Robert Griesemer

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
parent 4a431983
......@@ -3,7 +3,7 @@ The Go Programming Language Specification (DRAFT)
Robert Griesemer, Rob Pike, Ken Thompson
(January 27, 2009)
(January 30, 2009)
----
......@@ -1215,7 +1215,7 @@ types (§Types).
StructType = "struct" [ "{" [ FieldDeclList ] "}" ] .
FieldDeclList = FieldDecl { ";" FieldDecl } [ ";" ] .
FieldDecl = (IdentifierList CompleteType | TypeName) [ Tag ] .
Tag = string_lit .
Tag = StringLit .
// An empty struct.
struct {}
......@@ -1225,7 +1225,7 @@ types (§Types).
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 @@ Function types
----
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 @@ no additional arguments). If the parameters are named, the identifier
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 @@ the set of methods specified by the interface type, and the value "nil".
InterfaceType = "interface" [ "{" [ MethodSpecList ] "}" ] .
MethodSpecList = MethodSpec { ";" MethodSpec } [ ";" ] .
MethodSpec = IdentifierList FunctionType .
MethodSpec = IdentifierList Signature .
// An interface specifying a basic File type.
interface {
......@@ -1704,8 +1715,8 @@ For instance, given the declarations
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 @@ Operands denote the elementary values in an expression.
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 @@ 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).
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 @@ TODO add examples
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 @@ A method is called using the notation
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 @@ Address operators
TODO: Need to talk about unary "*", clean up section below.
Given a function f, declared as
func f(a int) int;
taking the address of f with the expression
&f
TODO: This text needs to be cleaned up and go elsewhere, there are no address
operators involved.
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 @@ pointer to function. Consider the type T with method M:
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).
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.
using the variable t (not the type T). The expression is a pointer to a
function, with type
The expression t.M is a function value with type
*(t *T, a int) int
func (t *T, a int) int
and may be invoked only as a function, not a method:
and may be invoked only as a function, not as a method:
var f *(t *T, a int) int;
f = &t.M;
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 @@ and the "else" branch. If Expression evaluates to true,
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 @@ the variable is initialized once before the statement is entered.
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 @@ Switch statements
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 @@ Function declarations
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 @@ 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
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 @@ through an import declaration:
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.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment