Deriving functions from methods
DELTA=238 (118 added, 116 deleted, 4 changed) OCL=34653 CL=34660
This commit is contained in:
parent
1c9e4b358f
commit
01cadde597
242
doc/go_spec.html
242
doc/go_spec.html
@ -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,122 +2710,6 @@ to by the operand.
|
|||||||
*pf(x)
|
*pf(x)
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<p>
|
|
||||||
<font color=red>TODO: This text needs to be cleaned up and go elsewhere, there are no address
|
|
||||||
operators involved.
|
|
||||||
</font>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Methods are a form of function and a method ``value'' has a function type.
|
|
||||||
Consider the type T with method M:
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
type T struct {
|
|
||||||
a int;
|
|
||||||
}
|
|
||||||
func (tp *T) M(a int) int;
|
|
||||||
var t *T;
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
To construct the value of method M, one writes
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
t.M
|
|
||||||
</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>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
The expression t.M is a function value with type
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
func (t *T, a int) int
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
and may be invoked only as a function, not as a method:
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
var f func (t *T, a int) int;
|
|
||||||
f = t.M;
|
|
||||||
x := f(t, 7);
|
|
||||||
</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
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
t.M(args)
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
is equivalent to the function call
|
|
||||||
</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>
|
|
||||||
</p>
|
|
||||||
<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
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
var t1 *T1;
|
|
||||||
var t2 *T2;
|
|
||||||
var i I = t1;
|
|
||||||
m := i.M;
|
|
||||||
m(t2, 7);
|
|
||||||
</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
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
func (recv I, a int) {
|
|
||||||
recv.M(a);
|
|
||||||
}
|
|
||||||
</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, &x }).
|
|
||||||
(TBD: is it an implementation restriction or fact?)
|
|
||||||
</font>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h3 id="Communication_operators">Communication operators</h3>
|
<h3 id="Communication_operators">Communication operators</h3>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@ -2915,10 +2799,128 @@ 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
|
<font color=red>TODO: Probably in a separate section, communication semantics
|
||||||
need to be presented regarding send, receive, select, and goroutines.</font>
|
need to be presented regarding send, receive, select, and goroutines.</font>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<h3 id="Method_expressions">Method expressions</h3>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
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 class="grammar">
|
||||||
|
MethodExpr = ReceiverType "." MethodName .
|
||||||
|
ReceiverType = TypeName | "(" "*" TypeName ")" .
|
||||||
|
MethodName = identifier .
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
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>
|
||||||
|
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>
|
||||||
|
The expression
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
T.Mv
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
yields a function equivalent to <code>Mv</code> but
|
||||||
|
with an explicit receiver as its first argument; it has signature
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
func (tv T, a int) int
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
That function may be called normally with an explicit receiver, so
|
||||||
|
these three invocations are equivalent:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
t.Mv(7)
|
||||||
|
T.Mv(t, 7)
|
||||||
|
f := T.Mv; f(t, 7)
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Similarly, the expression
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
(*T).Mp
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
yields a function value representing <code>Mp</code> with signature
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
func (tp *T, f float) float
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
For a method with a value receiver, one can derive a function
|
||||||
|
with an explicit pointer receiver, so
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
(*T).Mv
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
yields a function value representing <code>Mv</code> with signature
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
func (tv *T, f int) int
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
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>
|
||||||
|
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>
|
<h3 id="Constant_expressions">Constant expressions</h3>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@ -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>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user