Commit 01cadde5 authored by Rob Pike's avatar Rob Pike

Deriving functions from methods

DELTA=238  (118 added, 116 deleted, 4 changed)
OCL=34653
CL=34660
parent 1c9e4b35
...@@ -1750,7 +1750,7 @@ and a type. ...@@ -1750,7 +1750,7 @@ and a type.
Operands denote the elementary values in an expression. Operands denote the elementary values in an expression.
<pre class="ebnf"> <pre class="ebnf">
Operand = Literal | QualifiedIdent | "(" Expression ")" . Operand = Literal | QualifiedIdent | MethodExpr | "(" Expression ")" .
Literal = BasicLit | CompositeLit | FunctionLit . Literal = BasicLit | CompositeLit | FunctionLit .
BasicLit = int_lit | float_lit | char_lit | StringLit . BasicLit = int_lit | float_lit | char_lit | StringLit .
</pre> </pre>
...@@ -2710,213 +2710,215 @@ to by the operand. ...@@ -2710,213 +2710,215 @@ to by the operand.
*pf(x) *pf(x)
</pre> </pre>
<h3 id="Communication_operators">Communication operators</h3>
<p> <p>
<font color=red>TODO: This text needs to be cleaned up and go elsewhere, there are no address The term <i>channel</i> means "value of <a href="#Channel_types">channel type</a>".
operators involved.
</font>
</p> </p>
<p> <p>
Methods are a form of function and a method ``value'' has a function type. The send operation uses the binary operator "&lt;-", which operates on
Consider the type T with method M: a channel and a value (expression):
</p> </p>
<pre> <pre>
type T struct { ch <- 3
a int;
}
func (tp *T) M(a int) int;
var t *T;
</pre> </pre>
<p> <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> </p>
<pre> <pre>
t.M ok := ch <- 3;
if ok { print("sent") } else { print("not sent") }
if ch <- 3 { print("sent") } else { print("not sent") }
</pre> </pre>
<p> <p>
using the variable t (not the type T). In other words, if the program tests the value of a send operation,
<font color=red>TODO: It makes perfect sense to be able to say T.M (in fact, it makes more the send is non-blocking and the value of the expression is the
sense then t.M, since only the type T is needed to find the method M, i.e., success of the operation. If the program does not test the value,
its address). TBD. the operation blocks until it succeeds.
</font>
</p> </p>
<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> </p>
<pre> <pre>
func (t *T, a int) int <-ch
</pre> </pre>
<p> <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> </p>
<pre> <pre>
var f func (t *T, a int) int; v1 := <-ch
f = t.M; v2 = <-ch
x := f(t, 7); f(<-ch)
<-strobe // wait until clock pulse
</pre> </pre>
<p> <p>
Note that one does not write t.f(7); taking the value of a method demotes If a receive expression is used in an assignment or initialization of the form
it to a function.
</p>
<p>
In general, given type T with method M and variable t of type T,
the method invocation
</p> </p>
<pre> <pre>
t.M(args) x, ok = <-ch
x, ok := <-ch
var x, ok = <-ch
</pre> </pre>
<p> <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> </p>
<pre>
(t.M)(t, args)
</pre>
<p> <p>
<font color=red> <font color=red>TODO: Probably in a separate section, communication semantics
TODO: should probably describe the effect of (t.m) under §<a href="#Expressions_if_t">Expressions if t</a>.m need to be presented regarding send, receive, select, and goroutines.</font>
denotes a method: Effect is as described above, converts into function.
</font>
</p> </p>
<h3 id="Method_expressions">Method expressions</h3>
<p> <p>
If T is an interface type, the expression t.M does not determine which If <code>M</code> is in the method set of type <code>T</code>,
underlying type's M is called until the point of the call itself. Thus given <code>T.M</code> is a function that is callable as a regular function
T1 and T2, both implementing interface I with method M, the sequence with the same arguments as <code>M</code> prefixed by an additional
argument that is the receiver of the method.
</p> </p>
<pre> <pre class="grammar">
var t1 *T1; MethodExpr = ReceiverType "." MethodName .
var t2 *T2; ReceiverType = TypeName | "(" "*" TypeName ")" .
var i I = t1; MethodName = identifier .
m := i.M;
m(t2, 7);
</pre> </pre>
<p> <p>
will invoke t2.M() even though m was constructed with an expression involving Consider a struct type <code>T</code> with two methods,
t1. Effectively, the value of m is a function literal <code>Mv</code>, whose receiver is of type <code>T</code>, and
<code>Mp</code>, whose receiver is of type <code>*T</code>.
</p> </p>
<pre> <pre>
func (recv I, a int) { type T struct {
recv.M(a); 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> </pre>
<p> <p>
that is automatically created. The expression
</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>
</p> </p>
<h3 id="Communication_operators">Communication operators</h3> <pre>
T.Mv
</pre>
<p> <p>
The term <i>channel</i> means "value of <a href="#Channel_types">channel type</a>". yields a function equivalent to <code>Mv</code> but
</p> with an explicit receiver as its first argument; it has signature
<p>
The send operation uses the binary operator "&lt;-", which operates on
a channel and a value (expression):
</p> </p>
<pre> <pre>
ch <- 3 func (tv T, a int) int
</pre> </pre>
<p> <p>
The send operation sends the value on the channel. Both the channel That function may be called normally with an explicit receiver, so
and the expression are evaluated before communication begins. these three invocations are equivalent:
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> </p>
<pre> <pre>
ok := ch <- 3; t.Mv(7)
if ok { print("sent") } else { print("not sent") } T.Mv(t, 7)
f := T.Mv; f(t, 7)
if ch <- 3 { print("sent") } else { print("not sent") }
</pre> </pre>
<p> <p>
In other words, if the program tests the value of a send operation, Similarly, the expression
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>
<pre>
(*T).Mp
</pre>
<p> <p>
The receive operation uses the prefix unary operator "&lt;-". yields a function value representing <code>Mp</code> with signature
The value of the expression is the value received, whose type
is the element type of the channel.
</p> </p>
<pre> <pre>
<-ch func (tp *T, f float) float
</pre> </pre>
<p> <p>
The expression blocks until a value is available, which then can For a method with a value receiver, one can derive a function
be assigned to a variable or used like any other expression. with an explicit pointer receiver, so
If the receive expression does not save the value, the value is
discarded.
</p> </p>
<pre> <pre>
v1 := <-ch (*T).Mv
v2 = <-ch
f(<-ch)
<-strobe // wait until clock pulse
</pre> </pre>
<p> <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> </p>
<pre> <pre>
x, ok = <-ch func (tv *T, f int) int
x, ok := <-ch
var x, ok = <-ch
</pre> </pre>
<p> <p>
the receive operation becomes non-blocking. Such a function indirects through the receiver to create a value
If the operation can proceed, the boolean variable to pass as the receiver to the underlying method;
<code>ok</code> will be set to <code>true</code> the method does not overwrite the value whose address is passed in
and the value stored in <code>x</code>; otherwise the function call.
<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> </p>
<p> <p>
<font color=red>TODO: Probably in a separate section, communication semantices The final case, a value-receiver function for a pointer-receiver method,
need to be presented regarding send, receive, select, and goroutines.</font> 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> </p>
<h3 id="Constant_expressions">Constant expressions</h3> <h3 id="Constant_expressions">Constant expressions</h3>
...@@ -4309,8 +4311,8 @@ mentions <code>B</code>, or mentions a function that ...@@ -4309,8 +4311,8 @@ mentions <code>B</code>, or mentions a function that
mentions <code>B</code>, recursively. mentions <code>B</code>, recursively.
If two items are not interdependent, they will be initialized If two items are not interdependent, they will be initialized
in the order they appear in the source. in the order they appear in the source.
Since the dependency analysis is done per package, it can be Since the dependency analysis is done per package, it can produce
defeated if <code>A</code>'s initializer calls a function defined unspecified results if <code>A</code>'s initializer calls a function defined
in another package that refers to <code>B</code>. in another package that refers to <code>B</code>.
</p> </p>
<p> <p>
......
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