Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
go
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
go
Commits
01cadde5
Commit
01cadde5
authored
Sep 15, 2009
by
Rob Pike
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Deriving functions from methods
DELTA=238 (118 added, 116 deleted, 4 changed) OCL=34653 CL=34660
parent
1c9e4b35
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
121 additions
and
119 deletions
+121
-119
doc/go_spec.html
doc/go_spec.html
+121
-119
No files found.
doc/go_spec.html
View file @
01cadde5
...
...
@@ -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 "
<
-", 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 "
<
-".
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,
&
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 "
<
-", 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 "
<
-".
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
b
e
defeated
if
<code>
A
</code>
's initializer calls a function defined
Since the dependency analysis is done per package, it can
produc
e
unspecified results
if
<code>
A
</code>
's initializer calls a function defined
in another package that refers to
<code>
B
</code>
.
</p>
<p>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment