4

I was under the impression that despite the differences in syntax, function a and function b below were logically equivalent. However, they are not and I do not understand the difference between them.

It seems to me that they are both assigning:

  • the value of x to the variable z,
  • the value of y to the variable x, and
  • the value of x+y to the variable y.

Could anyone help clear up my misunderstanding regarding the multiple variable assignment and the logical difference between function a and function b?

package main

import "fmt"

func a() (int, int, int) {
    x:=1
    y:=2
    z:=3

    z = x
    x = y
    y = x+y

    return x, y, z
}

func b() (int, int, int) {
    x:=1
    y:=2
    z:=3

    z, x, y = x, y, x+y

    return x, y, z
}

func main() {
    fmt.Println(a()) // prints 2 4 1
    fmt.Println(b()) // prints 2 3 1
}

3 Answers 3

5

Assignment can be thought of as an "atomic" operation. That is, it's useful to think that all values on the left hand side of the = are "frozen" until all of the operations are finished.

Consider the following program:

package main

import "fmt"

func swap() (int, int) {
    x := 1
    y := 2
    x, y = y, x
    return x, y
}

func main() {
    fmt.Println(swap()) // prints 2 1
}

Without this "freezing" behaviour, you would get 2 for both x and y, which is probably not what you'd expect from the code. It's also probably easier to reason about the semantics of this "freezing" behaviour than if the "cascading" approach were taken.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you so much. That's an excellent answer. And thank you everyone for your help.
2

The simple answer is because it's all one statement and the value of y hasn't been updated to 2 at the point when x+y is evaluated. IE the expression on the right hand side is evaluated prior to any assignment. In the other case everything happens on step at a time so ofc y's value has been updated to 2 and you get four.

Interesting problem for academic purposes, terrible code in real life so please don't write anything like that in a real program.

Comments

2

The Go Programming Language Specification

Assignments

the number of operands on the left must equal the number of expressions on the right, each of which must be single-valued, and the nth expression on the right is assigned to the nth operand on the left:

one, two, three = '一', '二', '三'

The blank identifier provides a way to ignore right-hand side values in an assignment:

_ = x       // evaluate x but ignore it
x, _ = f()  // evaluate f() but ignore second result value

The assignment proceeds in two phases. First, the operands of index expressions and pointer indirections (including implicit pointer indirections in selectors) on the left and the expressions on the right are all evaluated in the usual order. Second, the assignments are carried out in left-to-right order.

Tuple assignments are two phase assignment. First, the operands of index expressions and pointer indirections (including implicit pointer indirections in selectors) on the left and the expressions on the right are all evaluated in the usual order. Second, the assignments are carried out in left-to-right order.

For example,

package main

import "fmt"

func a() (int, int, int) {
    x := 1
    y := 2
    z := 3

    // phase 1
    tx := x
    ty := y

    // phase 2
    z = tx
    x = ty
    y = tx + ty

    return x, y, z
}

func b() (int, int, int) {
    x := 1
    y := 2
    z := 3

    z, x, y = x, y, x+y

    return x, y, z
}

func main() {
    fmt.Println(a()) 
    fmt.Println(b()) 
}

Output:

2 3 1
2 3 1

1 Comment

Thank you for replying so quickly.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.