Commit 7eb7ff2b authored by Rob Pike's avatar Rob Pike

new channel syntax

select cleans up too

SVN=127816
parent 814320c8
...@@ -4,7 +4,7 @@ The Go Programming Language (DRAFT) ...@@ -4,7 +4,7 @@ The Go Programming Language (DRAFT)
Robert Griesemer, Rob Pike, Ken Thompson Robert Griesemer, Rob Pike, Ken Thompson
---- ----
(July 8, 2008) (July 16, 2008)
This document is a semi-formal specification/proposal for a new This document is a semi-formal specification/proposal for a new
systems programming language. The document is under active systems programming language. The document is under active
...@@ -155,7 +155,7 @@ Multithreading and channels ...@@ -155,7 +155,7 @@ Multithreading and channels
Go supports multithreaded programming directly. A function may Go supports multithreaded programming directly. A function may
be invoked as a parallel thread of execution. Communication and be invoked as a parallel thread of execution. Communication and
synchronization is provided through channels and their associated synchronization are provided through channels and their associated
language support. language support.
...@@ -186,19 +186,19 @@ Here is a complete example Go program that implements a concurrent prime sieve: ...@@ -186,19 +186,19 @@ Here is a complete example Go program that implements a concurrent prime sieve:
package main package main
// Send the sequence 2, 3, 4, ... to channel 'ch'. // Send the sequence 2, 3, 4, ... to channel 'ch'.
func Generate(ch *chan> int) { func Generate(ch *chan-< int) {
for i := 2; ; i++ { for i := 2; ; i++ {
>ch = i // Send 'i' to channel 'ch'. ch -< i // Send 'i' to channel 'ch'.
} }
} }
// Copy the values from channel 'in' to channel 'out', // Copy the values from channel 'in' to channel 'out',
// removing those divisible by 'prime'. // removing those divisible by 'prime'.
func Filter(in *chan< int, out *chan> int, prime int) { func Filter(in *chan<- int, out *chan-< int, prime int) {
for { for {
i := <in; // Receive value of new variable 'i' from 'in'. i := <-in; // Receive value of new variable 'i' from 'in'.
if i % prime != 0 { if i % prime != 0 {
>out = i // Send 'i' to channel 'out'. out -< i // Send 'i' to channel 'out'.
} }
} }
} }
...@@ -208,7 +208,7 @@ Here is a complete example Go program that implements a concurrent prime sieve: ...@@ -208,7 +208,7 @@ Here is a complete example Go program that implements a concurrent prime sieve:
ch := new(chan int); // Create a new channel. ch := new(chan int); // Create a new channel.
go Generate(ch); // Start Generate() as a subprocess. go Generate(ch); // Start Generate() as a subprocess.
for { for {
prime := <ch; prime := <-ch;
printf("%d\n", prime); printf("%d\n", prime);
ch1 := new(chan int); ch1 := new(chan int);
go Filter(ch, ch1, prime); go Filter(ch, ch1, prime);
...@@ -728,12 +728,12 @@ By conversion or assignment, it may be restricted only to send or ...@@ -728,12 +728,12 @@ By conversion or assignment, it may be restricted only to send or
to receive; such a restricted channel to receive; such a restricted channel
is called a 'send channel' or a 'receive channel'. is called a 'send channel' or a 'receive channel'.
ChannelType = "chan" [ "<" | ">" ] ValueType . ChannelType = "chan" [ "<-" | "-<" ] ValueType .
chan any // a generic channel chan any // a generic channel
chan int // a channel that can exchange only ints chan int // a channel that can exchange only ints
chan> float // a channel that can only be used to send floats chan-< float // a channel that can only be used to send floats
chan< any // a channel that can receive (only) values of any type chan<- any // a channel that can receive (only) values of any type
Channel variables always have type pointer to channel. Channel variables always have type pointer to channel.
It is an error to attempt to use a channel value and in It is an error to attempt to use a channel value and in
...@@ -931,7 +931,7 @@ Types are structurally equivalent: Two types are equivalent (``equal'') if they ...@@ -931,7 +931,7 @@ Types are structurally equivalent: Two types are equivalent (``equal'') if they
are constructed the same way from equivalent types. are constructed the same way from equivalent types.
For instance, all variables declared as "*int" have equivalent type, For instance, all variables declared as "*int" have equivalent type,
as do all variables declared as "map [string] chan int". as do all variables declared as "map [string] *chan int".
More precisely, two struct types are equivalent if they have exactly the same fields More precisely, two struct types are equivalent if they have exactly the same fields
in the same order, with equal field names and types. For all other composite types, in the same order, with equal field names and types. For all other composite types,
...@@ -1215,13 +1215,14 @@ Expression syntax is based on that of C but with fewer precedence levels. ...@@ -1215,13 +1215,14 @@ Expression syntax is based on that of C but with fewer precedence levels.
ConversionType = TypeName | ArrayType | MapType | StructType | InterfaceType . ConversionType = TypeName | ArrayType | MapType | StructType | InterfaceType .
Allocation = "new" "(" Type [ "," ExpressionList ] ")" . Allocation = "new" "(" Type [ "," ExpressionList ] ")" .
binary_op = log_op | rel_op | add_op | mul_op . binary_op = log_op | comm_op | rel_op | add_op | mul_op .
log_op = "||" | "&&" . log_op = "||" | "&&" .
rel_op = "==" | "!=" | "<" | "<=" | ">" | ">=". comm_op = "<-" | "-<" .
add_op = "+" | "-" | "|" | "^". rel_op = "==" | "!=" | "<" | "<=" | ">" | ">=" .
mul_op = "*" | "/" | "%" | "<<" | ">>" | "&". add_op = "+" | "-" | "|" | "^" .
mul_op = "*" | "/" | "%" | "<<" | ">>" | "&" .
unary_op = "+" | "-" | "!" | "^" | "<" | ">" | "*" | "&" . unary_op = "+" | "-" | "!" | "^" | "*" | "&" | "<-" .
Field selection and type assertions ('.') bind tightest, followed by indexing ('[]') Field selection and type assertions ('.') bind tightest, followed by indexing ('[]')
and then calls and conversions. The remaining precedence levels are as follows and then calls and conversions. The remaining precedence levels are as follows
...@@ -1230,10 +1231,11 @@ and then calls and conversions. The remaining precedence levels are as follows ...@@ -1230,10 +1231,11 @@ and then calls and conversions. The remaining precedence levels are as follows
Precedence Operator Precedence Operator
1 || 1 ||
2 && 2 &&
3 == != < <= > >= 3 <- -<
4 + - | ^ 4 == != < <= > >=
5 * / % << >> & 5 + - | ^
6 + - ! ^ < > * & (unary) 6 * / % << >> &
7 + - ! ^ * <- (unary) & (unary)
For integer values, / and % satisfy the following relationship: For integer values, / and % satisfy the following relationship:
...@@ -1291,7 +1293,7 @@ Examples of general expressions ...@@ -1291,7 +1293,7 @@ Examples of general expressions
x <= f() x <= f()
^a >> b ^a >> b
f() || g() f() || g()
x == y + 1 && <chan_ptr > 0 x == y + 1 && <-chan_ptr > 0
The nil value The nil value
...@@ -1566,11 +1568,10 @@ Note that ++ and -- are not operators for expressions. ...@@ -1566,11 +1568,10 @@ Note that ++ and -- are not operators for expressions.
Assignments Assignments
---- ----
Assignment = SingleAssignment | TupleAssignment | Send . Assignment = SingleAssignment | TupleAssignment .
SingleAssignment = PrimaryExpr assign_op Expression . SingleAssignment = PrimaryExpr assign_op Expression .
TupleAssignment = PrimaryExprList assign_op ExpressionList . TupleAssignment = PrimaryExprList assign_op ExpressionList .
PrimaryExprList = PrimaryExpr { "," PrimaryExpr } . PrimaryExprList = PrimaryExpr { "," PrimaryExpr } .
Send = ">" Expression "=" Expression .
assign_op = [ add_op | mul_op ] "=" . assign_op = [ add_op | mul_op ] "=" .
...@@ -1580,6 +1581,7 @@ or an array index. ...@@ -1580,6 +1581,7 @@ or an array index.
x = 1 x = 1
*p = f() *p = f()
a[i] = 23 a[i] = 23
k = <-ch
As in C, arithmetic binary operators can be combined with assignments: As in C, arithmetic binary operators can be combined with assignments:
...@@ -1608,20 +1610,86 @@ the variable is unchanged, and the boolean value is set to false. ...@@ -1608,20 +1610,86 @@ the variable is unchanged, and the boolean value is set to false.
value, present = map_var[key] value, present = map_var[key]
Analogously, receiving a value from a channel can be written as a tuple assignment. In assignments, the type of the expression must match the type of the left-hand side.
value, success = <chan_var Communication
----
If the receive operation would block, the boolean is set to false. The syntax presented above covers communication operations. This
This provides a mechanism to avoid blocking on a receive operation. section describes their form and function.
Sending on a channel is a form of assignment. The left hand side expression Here the term "channel" means "variable of type *chan".
must denote a channel pointer value.
>chan_ptr = value A channel is created by allocating it:
In assignments, the type of the expression must match the type of the left-hand side. ch := new(chan int)
An optional argument to new() specifies a buffer size for an
asynchronous channel; if absent or zero, the channel is synchronous:
sync_chan := new(chan int)
buffered_chan := new(chan int, 10)
The send operator is the binary operator "-<", which operates on
a channel and a value (expression):
ch -< 3
In this form, the send operation is an (expression) statement that
blocks until the send can proceed, at which point the value is
transmitted on the channel.
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. These two examples are equivalent:
ok := ch -< 3;
if ok { print "sent" } else { print "not sent" }
if ch -< 3 { print "sent" } else { print "not sent" }
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 receive uses the binary operator "<-", analogous to send but
with the channel on the right:
v1 <- ch
As with send operations, in expression context this form may
be used as a boolean and makes the receive non-blocking:
ok := e <- ch;
if ok { print "received", e } else { print "did not receive" }
The receive operator may also be used as a prefix unary operator
on a channel.
<- ch
The expression blocks until a value is available, which then can
be assigned to a variable or used like any other expression:
v1 := <-ch
v2 = <-ch
f(<-ch)
If the receive expression does not save the value, the value is
discarded:
<- strobe // wait until clock pulse
Finally, as a special case unique to receive, the forms
e, ok := <-ch
e, ok = <-ch
allow the operation to declare and/or assign the received value and
the boolean indicating success. These two forms are always
non-blocking.
Go statements Go statements
---- ----
...@@ -1635,7 +1703,7 @@ function to complete. ...@@ -1635,7 +1703,7 @@ function to complete.
go Server() go Server()
go func(ch chan> bool) { for { sleep(10); >ch = true; }} (c) go func(ch chan-< bool) { for { sleep(10); ch -< true; }} (c)
Return statements Return statements
...@@ -1773,9 +1841,10 @@ cases all referring to communication operations. ...@@ -1773,9 +1841,10 @@ cases all referring to communication operations.
SelectStat = "select" "{" { CommClause } "}" . SelectStat = "select" "{" { CommClause } "}" .
CommClause = CommCase [ StatementList [ ";" ] ] . CommClause = CommCase [ StatementList [ ";" ] ] .
CommCase = ( "default" | ( "case" ( SendCase | RecvCase) ) ) ":" . CommCase = ( "default" | ( "case" ( SendCase | RecvCase) ) ) ":" .
SendCase = Send . SendCase = SendExpr .
RecvCase = [ identifier "=" ] RecvExpr . RecvCase = RecvExpr .
RecvExpr = "<" Expression . SendExpr = Expression "-<" Expression .
RecvExpr = [ identifier ] "<-" Expression .
The select statement evaluates all the channel (pointers) involved. The select statement evaluates all the channel (pointers) involved.
If any of the channels can proceed, the corresponding communication If any of the channels can proceed, the corresponding communication
...@@ -1793,9 +1862,9 @@ which single communication will execute. ...@@ -1793,9 +1862,9 @@ which single communication will execute.
var c, c1, c2 *chan int; var c, c1, c2 *chan int;
select { select {
case i1 = <c1: case i1 <-c1:
printf("received %d from c1\n", i1); printf("received %d from c1\n", i1);
case >c2 = i2: case c2 -< i2:
printf("sent %d to c2\n", i2); printf("sent %d to c2\n", i2);
default: default:
printf("no communication\n"); printf("no communication\n");
...@@ -1803,8 +1872,8 @@ which single communication will execute. ...@@ -1803,8 +1872,8 @@ which single communication will execute.
for { // send random sequence of bits to c for { // send random sequence of bits to c
select { select {
case >c = 0: // note: no statement, no fallthrough, no folding of cases case c -< 0: // note: no statement, no fallthrough, no folding of cases
case >c = 1: case c -< 1:
} }
} }
...@@ -1812,13 +1881,13 @@ which single communication will execute. ...@@ -1812,13 +1881,13 @@ which single communication will execute.
var i int; var i int;
var f float; var f float;
select { select {
case i = <ca: case i <- ca:
printf("received int %d from ca\n", i); printf("received int %d from ca\n", i);
case f = <ca: case f <- ca:
printf("received float %f from ca\n", f); printf("received float %f from ca\n", f);
} }
TODO: do we allow case i := <c: ? TODO: do we allow case i := <-c: ?
TODO: need to precise about all the details but this is not the right doc for that TODO: need to precise about all the details but this is not the right doc for that
......
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