bisgardo
bisgardo

Reputation: 4600

In Go, when are values copied in multivalue assignments?

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

Answers (1)

bisgardo
bisgardo

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(), and k(). However, the order of those events compared to the evaluation and indexing of x and the evaluation of y 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

Related Questions