]> Cypherpunks repositories - gostls13.git/commitdiff
Deriving functions from methods
authorRob Pike <r@golang.org>
Tue, 15 Sep 2009 22:56:44 +0000 (15:56 -0700)
committerRob Pike <r@golang.org>
Tue, 15 Sep 2009 22:56:44 +0000 (15:56 -0700)
DELTA=238  (118 added, 116 deleted, 4 changed)
OCL=34653
CL=34660

doc/go_spec.html

index abe26fc41929aa32fabd15a758a473c875a8e05d..6a21c6cabf413c353852d3abcb77324314e4cacb 100644 (file)
@@ -1750,7 +1750,7 @@ and a type.
 Operands denote the elementary values in an expression.
 
 <pre class="ebnf">
-Operand    = Literal | QualifiedIdent | "(" Expression ")" .
+Operand    = Literal | QualifiedIdent | MethodExpr | "(" Expression ")" .
 Literal    = BasicLit | CompositeLit | FunctionLit .
 BasicLit   = int_lit | float_lit | char_lit | StringLit .
 </pre>
@@ -2710,213 +2710,215 @@ to by the operand.
 *pf(x)
 </pre>
 
+<h3 id="Communication_operators">Communication operators</h3>
+
 <p>
-<font color=red>TODO: This text needs to be cleaned up and go elsewhere, there are no address
-operators involved.
-</font>
+The term <i>channel</i> means "value of <a href="#Channel_types">channel type</a>".
 </p>
 <p>
-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 "&lt;-", which operates on
+a channel and a value (expression):
 </p>
 
 <pre>
-type T struct {
-       a int;
-}
-func (tp *T) M(a int) int;
-var t *T;
+ch <- 3
 </pre>
 
 <p>
-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.
+</p>
+<p>
+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:
 </p>
 
 <pre>
-t.M
+ok := ch <- 3;
+if ok { print("sent") } else { print("not sent") }
+
+if ch <- 3 { print("sent") } else { print("not sent") }
 </pre>
 
 <p>
-using the variable t (not the type T).
-<font color=red>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.
-</font>
+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.
 </p>
-
 <p>
-The expression t.M is a function value with type
+The receive operation uses the prefix unary operator "&lt;-".
+The value of the expression is the value received, whose type
+is the element type of the channel.
 </p>
 
 <pre>
-func (t *T, a int) int
+<-ch
 </pre>
 
 <p>
-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.
 </p>
 
 <pre>
-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
 </pre>
 
 <p>
-Note that one does not write t.f(7); taking the value of a method demotes
-it to a function.
-</p>
-
-<p>
-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
 </p>
 
 <pre>
-t.M(args)
+x, ok = <-ch
+x, ok := <-ch
+var x, ok = <-ch
 </pre>
 
 <p>
-is equivalent to the function call
+the receive operation becomes non-blocking.
+If the operation can proceed, the boolean variable
+<code>ok</code> will be set to <code>true</code>
+and the value stored in <code>x</code>; otherwise
+<code>ok</code> is set
+to <code>false</code> and <code>x</code> is set to the
+zero value for its type (§<a href="#The_zero_value">The zero value</a>).
 </p>
 
-<pre>
-(t.M)(t, args)
-</pre>
-
 <p>
-<font color=red>
-TODO: should probably describe the effect of (t.m) under §<a href="#Expressions_if_t">Expressions if t</a>.m
-denotes a method: Effect is as described above, converts into function.
-</font>
+<font color=red>TODO: Probably in a separate section, communication semantics
+need to be presented regarding send, receive, select, and goroutines.</font>
 </p>
+
+<h3 id="Method_expressions">Method expressions</h3>
+
 <p>
-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 <code>M</code> is in the method set of type <code>T</code>,
+<code>T.M</code> is a function that is callable as a regular function
+with the same arguments as <code>M</code> prefixed by an additional
+argument that is the receiver of the method.
 </p>
 
-<pre>
-var t1 *T1;
-var t2 *T2;
-var i I = t1;
-m := i.M;
-m(t2, 7);
+<pre class="grammar">
+MethodExpr    = ReceiverType "." MethodName .
+ReceiverType  = TypeName | "(" "*" TypeName ")" .
+MethodName    = identifier .
 </pre>
 
 <p>
-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 <code>T</code> with two methods,
+<code>Mv</code>, whose receiver is of type <code>T</code>, and
+<code>Mp</code>, whose receiver is of type <code>*T</code>.
 </p>
 
 <pre>
-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;
 </pre>
 
 <p>
-that is automatically created.
-</p>
-<p>
-<font color=red>
-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, &amp;x }).
-(TBD: is it an implementation restriction or fact?)
-</font>
+The expression
 </p>
 
-<h3 id="Communication_operators">Communication operators</h3>
+<pre>
+T.Mv
+</pre>
 
 <p>
-The term <i>channel</i> means "value of <a href="#Channel_types">channel type</a>".
-</p>
-<p>
-The send operation uses the binary operator "&lt;-", which operates on
-a channel and a value (expression):
+yields a function equivalent to <code>Mv</code> but
+with an explicit receiver as its first argument; it has signature
 </p>
 
 <pre>
-ch <- 3
+func (tv T, a int) int
 </pre>
 
 <p>
-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.
-</p>
-<p>
-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:
 </p>
 
 <pre>
-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)
 </pre>
 
 <p>
-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
 </p>
+
+<pre>
+(*T).Mp
+</pre>
+
 <p>
-The receive operation uses the prefix unary operator "&lt;-".
-The value of the expression is the value received, whose type
-is the element type of the channel.
+yields a function value representing <code>Mp</code> with signature
 </p>
 
 <pre>
-<-ch
+func (tp *T, f float) float
 </pre>
 
 <p>
-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
 </p>
 
 <pre>
-v1 := <-ch
-v2 = <-ch
-f(<-ch)
-<-strobe  // wait until clock pulse
+(*T).Mv
 </pre>
 
 <p>
-If a receive expression is used in an assignment or initialization of the form
+yields a function value representing <code>Mv</code> with signature
 </p>
 
 <pre>
-x, ok = <-ch
-x, ok := <-ch
-var x, ok = <-ch
+func (tv *T, f int) int
 </pre>
 
 <p>
-the receive operation becomes non-blocking.
-If the operation can proceed, the boolean variable
-<code>ok</code> will be set to <code>true</code>
-and the value stored in <code>x</code>; otherwise
-<code>ok</code> is set
-to <code>false</code> and <code>x</code> is set to the
-zero value for its type (§<a href="#The_zero_value">The zero value</a>).
+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.
 </p>
 
 <p>
-<font color=red>TODO: Probably in a separate section, communication semantices
-need to be presented regarding send, receive, select, and goroutines.</font>
+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.
+</p>
+
+<p>
+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 <code>f := T.Mv</code>, <code>f</code> is invoked
+as <code>f(t, 7)</code> not <code>t.f(7)</code>.
+To construct a function that binds the receiver, use a
+<a href="Function_literals">closure</a>.
+</p>
+
+<p>
+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.
 </p>
 
 <h3 id="Constant_expressions">Constant expressions</h3>
@@ -4309,8 +4311,8 @@ mentions <code>B</code>, or mentions a function that
 mentions <code>B</code>, 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 <code>A</code>'s initializer calls a function defined
+Since the dependency analysis is done per package, it can produce
+unspecified results  if <code>A</code>'s initializer calls a function defined
 in another package that refers to <code>B</code>.
 </p>
 <p>