From 01cadde59761f2aade7ae45f41a145893b59cc71 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Tue, 15 Sep 2009 15:56:44 -0700 Subject: [PATCH] Deriving functions from methods DELTA=238 (118 added, 116 deleted, 4 changed) OCL=34653 CL=34660 --- doc/go_spec.html | 242 ++++++++++++++++++++++++----------------------- 1 file changed, 122 insertions(+), 120 deletions(-) diff --git a/doc/go_spec.html b/doc/go_spec.html index abe26fc4192..6a21c6cabf4 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -1750,7 +1750,7 @@ and a type. Operands denote the elementary values in an expression.
-Operand    = Literal | QualifiedIdent | "(" Expression ")" .
+Operand    = Literal | QualifiedIdent | MethodExpr | "(" Expression ")" .
 Literal    = BasicLit | CompositeLit | FunctionLit .
 BasicLit   = int_lit | float_lit | char_lit | StringLit .
 
@@ -2710,122 +2710,6 @@ to by the operand. *pf(x) -

-TODO: This text needs to be cleaned up and go elsewhere, there are no address -operators involved. - -

-

-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;
-}
-func (tp *T) M(a int) int;
-var t *T;
-
- -

-To construct the value of method M, one writes -

- -
-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. - -

- -

-The expression t.M is a function value with type -

- -
-func (t *T, a int) int
-
- -

-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 value of a method demotes -it to a function. -

- -

-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)
-
- -

- -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 method M, the sequence -

- -
-var t1 *T1;
-var t2 *T2;
-var i I = t1;
-m := i.M;
-m(t2, 7);
-
- -

-will invoke t2.M() even though m was constructed with an expression involving -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

@@ -2915,10 +2799,128 @@ zero value for its type (§The zero value).

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

+

Method expressions

+ +

+If M is in the method set of type T, +T.M is a function that is callable as a regular function +with the same arguments as M prefixed by an additional +argument that is the receiver of the method. +

+ +
+MethodExpr    = ReceiverType "." MethodName .
+ReceiverType  = TypeName | "(" "*" TypeName ")" .
+MethodName    = identifier .
+
+ +

+Consider a struct type T with two methods, +Mv, whose receiver is of type T, and +Mp, whose receiver is of type *T. +

+ +
+type T struct {
+	a int;
+}
+func (tv  T) Mv(a int)   int   { return 0 }  // value receiver
+func (tp *T) Mp(f float) float { return 1 }  // pointer receiver
+var t T;
+
+ +

+The expression +

+ +
+T.Mv
+
+ +

+yields a function equivalent to Mv but +with an explicit receiver as its first argument; it has signature +

+ +
+func (tv T, a int) int
+
+ +

+That function may be called normally with an explicit receiver, so +these three invocations are equivalent: +

+ +
+t.Mv(7)
+T.Mv(t, 7)
+f := T.Mv; f(t, 7)
+
+ +

+Similarly, the expression +

+ +
+(*T).Mp
+
+ +

+yields a function value representing Mp with signature +

+ +
+func (tp *T, f float) float
+
+ +

+For a method with a value receiver, one can derive a function +with an explicit pointer receiver, so +

+ +
+(*T).Mv
+
+ +

+yields a function value representing Mv with signature +

+ +
+func (tv *T, f int) int
+
+ +

+Such a function indirects through the receiver to create a value +to pass as the receiver to the underlying method; +the method does not overwrite the value whose address is passed in +the function call. +

+ +

+The final case, a value-receiver function for a pointer-receiver method, +is illegal because pointer-receiver methods are not in the method set +of the value type. +

+ +

+Function values derived from methods are called with function call syntax; +the receiver is provided as the first argument to the call. +That is, given f := T.Mv, f is invoked +as f(t, 7) not t.f(7). +To construct a function that binds the receiver, use a +closure. +

+ +

+It is legal to derive a function value from a method of an interface type. +The resulting function takes an explicit receiver of that interface type. +

+

Constant expressions

@@ -4309,8 +4311,8 @@ mentions B, or mentions a function that mentions B, recursively. If two items are not interdependent, they will be initialized in the order they appear in the source. -Since the dependency analysis is done per package, it can be -defeated if A's initializer calls a function defined +Since the dependency analysis is done per package, it can produce +unspecified results if A's initializer calls a function defined in another package that refers to B.