Reputation: 4600
Consider the following Go function (playground), which was evaluated with Go 1.8:
func f() (int, bool) {
i := 0
c := make(chan bool)
go func() {
time.Sleep(1 * time.Second)
i = 1
c <- true
}()
// In practice, `i` will always be 0 here.
return i, <-c // returns 1, true
}
As stated in the comments, the function seem to always copy i
after c
has yielded a value. As this happens ~1s after encountering the return statement, this is not what I expected.
The behavior is the same if the value order is reversed in the return and also if the return is replaced by assignment.
Note that I'm not claiming this behavior to be wrong - just unexpected. In fact, this will almost always be what you want to happen.
The question therefore is if this intended/specified behavior that can be relied on?
The spec section on the receive operator doesn't state exactly when it blocks the thread in cases like this.
Upvotes: 0
Views: 60
Reputation: 4600
According to the spec section on order of evaluation, functions and receive operations in a statement like this are evaluated from left to right:
For example, in the (function-local) assignment
y[f()], ok = g(h(), i()+x[j()], <-c), k()
the function calls and communication happen in the order
f()
,h()
,i()
,j()
,<-c
,g()
, andk()
. However, the order of those events compared to the evaluation and indexing ofx
and the evaluation ofy
is not specified.
But as stated in the emphasized sentence, the order of variable evaluation is not specified.
The section gives another example that makes this even clearer:
a := 1
f := func() int { a++; return a }
x := []int{a, f()}
// x may be [1, 2] or [2, 2]: evaluation order between a and f() is not specified
So while the behavior is as desired, it is unfortunately not specified and cannot be relied on.
Upvotes: 1