Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

golang multiple assignment evaluation

Tags:

go

I'm confused on the concept of multiple assignment. Given the following code:

func fibonacci() func() int {
    current, next := 0, 1
    return func() int {
        current, next = next, current+next
        return current
    }
}

How is the assignment evaluated, given the fact that both variables appear on both the left and right side of the assignment?

like image 555
Jeroen Jacobs Avatar asked Feb 16 '18 23:02

Jeroen Jacobs


2 Answers

The Go Programming Language Specification

Assignments

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.


The usual example to illustrate multiple assignments is a swap. For example,

package main

import "fmt"

func main() {
    {
        i, j := 7, 42
        fmt.Println(i, j)
        // swap i and j - implicit temporaries
        i, j = j, i
        fmt.Println(i, j)
    }

    fmt.Println()

    {
        i, j := 7, 42
        fmt.Println(i, j)
        // swap i and j - explicit temporaries
        ti, tj := i, j
        i, j = tj, ti
        fmt.Println(i, j)
    }
}

Playground: https://play.golang.org/p/HcD9zq_7tqQ

Output:

7 42
42 7

7 42
42 7

The one statement multiple assignment, which uses implicit temporary variables, is equivalent to (a shorthand for) the two multiple assignment statements, which use explicit temporary variables.


Your fibonacci example translates, with explicit order and temporary variables, to:

package main

import "fmt"

func fibonacciMultiple() func() int {
    current, next := 0, 1
    return func() int {
        current, next = next, current+next
        return current
    }
}

func fibonacciSingle() func() int {
    current, next := 0, 1
    return func() int {

        // current, next = next, current+next
        // first phase, evaluation, left-to-right
        t1 := next
        t2 := current + next
        // second phase, assignmemt, left-to-right
        current = t1
        next = t2

        return current
    }
}

func main() {
    m := fibonacciMultiple()
    fmt.Println(m(), m(), m(), m(), m(), m())
    s := fibonacciSingle()
    fmt.Println(s(), s(), s(), s(), s(), s())
}

Playground: https://play.golang.org/p/XFq-0wyNke9

Output:

1 1 2 3 5 8
1 1 2 3 5 8
like image 140
peterSO Avatar answered Nov 17 '22 20:11

peterSO


The order is defined in Order of Evaluation in the language spec.

At package level, initialization dependencies determine the evaluation order of individual initialization expressions in variable declarations. Otherwise, when evaluating the operands of an expression, assignment, or return statement, all function calls, method calls, and communication operations are evaluated in lexical left-to-right order.

Which comes with a good example of complex evaluation order

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.

Operands are evaluated left to right. The fact that next is assigned to after the operands are evaluated is irrelevant.

Then there are the Assignments:

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.

So the order here is next then current+next. The result of next is assigned to current, then the result of current+next is assigned to next.

like image 3
JimB Avatar answered Nov 17 '22 18:11

JimB