From: Rob Pike Date: Tue, 15 Sep 2009 22:56:44 +0000 (-0700) Subject: Deriving functions from methods X-Git-Tag: weekly.2009-11-06~573 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=01cadde59761f2aade7ae45f41a145893b59cc71;p=gostls13.git Deriving functions from methods DELTA=238 (118 added, 116 deleted, 4 changed) OCL=34653 CL=34660 --- diff --git a/doc/go_spec.html b/doc/go_spec.html index abe26fc419..6a21c6cabf 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,213 +2710,215 @@ to by the operand. *pf(x) +

Communication operators

+

-TODO: This text needs to be cleaned up and go elsewhere, there are no address -operators involved. - +The term channel means "value of channel type".

-Methods are a form of function and a method ``value'' has a function type. -Consider the type T with method M: +The send operation uses the binary operator "<-", which operates on +a channel and a value (expression):

-type T struct {
-	a int;
-}
-func (tp *T) M(a int) int;
-var t *T;
+ch <- 3
 

-To construct the value of method M, one writes +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 on an unbuffered channel can proceed if a receiver is ready. +A send on a buffered channel can proceed if there is room in the buffer. +

+

+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. (The channel and +the expression to be sent are evaluated regardless.) +These two examples are equivalent:

-t.M
+ok := ch <- 3;
+if ok { print("sent") } else { print("not sent") }
+
+if ch <- 3 { print("sent") } else { print("not sent") }
 

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

-

-The expression t.M is a function value with type +The receive operation uses the prefix unary operator "<-". +The value of the expression is the value received, whose type +is the element type of the channel.

-func (t *T, a int) int
+<-ch
 

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

-var f func (t *T, a int) int;
-f = t.M;
-x := f(t, 7);
+v1 := <-ch
+v2 = <-ch
+f(<-ch)
+<-strobe  // wait until clock pulse
 

-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 +If a receive expression is used in an assignment or initialization of the form

-t.M(args)
+x, ok = <-ch
+x, ok := <-ch
+var x, ok = <-ch
 

-is equivalent to the function call +the receive operation becomes non-blocking. +If the operation can proceed, 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).

-
-(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. - +TODO: Probably in a separate section, communication semantics +need to be presented regarding send, receive, select, and goroutines.

+ +

Method expressions

+

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

-
-var t1 *T1;
-var t2 *T2;
-var i I = t1;
-m := i.M;
-m(t2, 7);
+
+MethodExpr    = ReceiverType "." MethodName .
+ReceiverType  = TypeName | "(" "*" TypeName ")" .
+MethodName    = identifier .
 

-will invoke t2.M() even though m was constructed with an expression involving -t1. Effectively, the value of m is a function literal +Consider a struct type T with two methods, +Mv, whose receiver is of type T, and +Mp, whose receiver is of type *T.

-func (recv I, a int) {
-	recv.M(a);
+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;
 

-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?) - +The expression

-

Communication operators

+
+T.Mv
+

-The term channel means "value of channel type". -

-

-The send operation uses the binary operator "<-", which operates on -a channel and a value (expression): +yields a function equivalent to Mv but +with an explicit receiver as its first argument; it has signature

-ch <- 3
+func (tv T, a int) int
 

-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 on an unbuffered channel can proceed if a receiver is ready. -A send on a buffered channel can proceed if there is room in the buffer. -

-

-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. (The channel and -the expression to be sent are evaluated regardless.) -These two examples are equivalent: +That function may be called normally with an explicit receiver, so +these three invocations are equivalent:

-ok := ch <- 3;
-if ok { print("sent") } else { print("not sent") }
-
-if ch <- 3 { print("sent") } else { print("not sent") }
+t.Mv(7)
+T.Mv(t, 7)
+f := T.Mv; f(t, 7)
 

-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. +Similarly, the expression

+ +
+(*T).Mp
+
+

-The receive operation uses the prefix unary operator "<-". -The value of the expression is the value received, whose type -is the element type of the channel. +yields a function value representing Mp with signature

-<-ch
+func (tp *T, f float) float
 

-The expression blocks until a value is available, which then can -be assigned to a variable or used like any other expression. -If the receive expression does not save the value, the value is -discarded. +For a method with a value receiver, one can derive a function +with an explicit pointer receiver, so

-v1 := <-ch
-v2 = <-ch
-f(<-ch)
-<-strobe  // wait until clock pulse
+(*T).Mv
 

-If a receive expression is used in an assignment or initialization of the form +yields a function value representing Mv with signature

-x, ok = <-ch
-x, ok := <-ch
-var x, ok = <-ch
+func (tv *T, f int) int
 

-the receive operation becomes non-blocking. -If the operation can proceed, 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). +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.

-TODO: Probably in a separate section, communication semantices -need to be presented regarding send, receive, select, and goroutines. +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.