Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

spec: order of evaluation of variables in return statement is not determined #25609

Open
zboya opened this issue May 28, 2018 · 11 comments

Comments

@zboya
Copy link

commented May 28, 2018

Please answer these questions before submitting your issue. Thanks!

What version of Go are you using (go version)?

go version
go version go1.10.2 darwin/amd64

What did you do?

package main

import "fmt"

func main() {
	m, i, j := testChange()
	fmt.Println("retun ", m, i, j)
}

func testChange() (int, interface{}, int) {
	m := 0
	i := 0

	f := func() int {
		m = 2
		i = 2
		return 99
	}

	return m, i, f()
}

What did you expect to see?

retun 2 2 99

What did you see instead?

retun 2 0 99

@cznic

This comment has been minimized.

Copy link
Contributor

commented May 28, 2018

This seems to be working as specified.

edit: Oversight, no more I think the above. 0 0 99 or 2 2 99.

@DeedleFake

This comment has been minimized.

Copy link

commented May 28, 2018

How is this working as specified? This seems to show a discrepancy in the behavior of assigning to a variable depending on whether it's an interface or not. Not trying to be accusatory; just curious what part of the spec covers this.

Edit: Better wording.

@cznic

This comment has been minimized.

Copy link
Contributor

commented May 28, 2018

Yup, I edited my post while you were writing yours. My apologies.

@fraenkel

This comment has been minimized.

Copy link
Contributor

commented May 28, 2018

There is no guaranteed order, see https://golang.org/ref/spec#Order_of_evaluation

@cznic

This comment has been minimized.

Copy link
Contributor

commented May 28, 2018

That seems to specify evaluating of a single expression. The order of evaluation of the expressions in the list of expressions of an return statement seems to be unspecified, so the evaluating m, i, f() in order i, f(), m would warrant the OP observed result.

I will now stop myself from polluting this issue. I'm no more sure about anything involved in it.

@ianlancetaylor

This comment has been minimized.

Copy link
Contributor

commented May 28, 2018

With Go 1.3 and later I get 2 0 99. With gccgo I get 0 0 99. With Go 1.0 to 1.3 I get 2 2 99.

I think this boils down to when we evaluate variables listed in the return statement. Do we load m and i before or after the call to f? I don't think the language spec currently specifies that. In other words, I think this is another example of #23188 (comment) .

I don't think the detail of the fact that this is an interface value affects this. It happens to change what the compiler does, but I don't think any specific ordering is required anyhow.

@ianlancetaylor ianlancetaylor changed the title The return value is an empty interface can't be change spec: order of evaluation of variables in return statement is not determined May 28, 2018

@ianlancetaylor ianlancetaylor added this to the Unplanned milestone May 28, 2018

@KISSMonX

This comment has been minimized.

Copy link

commented May 29, 2018

go1.10.2 darwin/amd64

image

@KISSMonX

This comment has been minimized.

Copy link

commented May 29, 2018

Test Code: https://play.golang.org/p/xnHqSQyrp_J

package main

import "fmt"

func main() {
	m, i, j := testChange00()
	fmt.Println("retun ", m.(int), i.(int), j.(int)) // 0 0 99
	fmt.Println("retun ", m, i, j)                   // 0 0 99

	a, b, c := testChange11()
	fmt.Println("retun ", a, b, c) // 2 2 99
}

// return type: int int int  				Result: 2 2 99
// return type: int int interface{} 			Result: 2 2 99
// return type: int interface{}, interface{} 		Result: 2 0 99
// return type: int interface{}, int 			Result: 2 0 99
// return type: interface{} interface{} interface{} 	Result: 0 0 99
// return type: interface{} interface{} int 		Result: 0 0 99
// return type: interface{} int int 			Result: 0 2 99
// return type: interface{} int interface{}		Result: 0 2 99
func testChange00() (interface{}, interface{}, interface{}) {
	m := 0
	i := 0

	f := func() int {
		m = 2
		i = 2
		return 99
	}

	return m, i, f()
}

func testChange11() (int, int, int) {
	m := 0
	i := 0

	f := func() int {
		m = 2
		i = 2
		return 99
	}

	return m, i, f()
}
@zboya

This comment has been minimized.

Copy link
Author

commented May 29, 2018

@KISSMonX that is the reason why I wonder, I think the interface dose affect the result.

@KISSMonX

This comment has been minimized.

Copy link

commented May 29, 2018

Yeah, indeed affected, but return type should not affect the order of evaluation.
Waiting for official reply. 😃

@ianlancetaylor

This comment has been minimized.

Copy link
Contributor

commented May 29, 2018

With the current spec, the order of evaluation is unpredictable. There is no one correct answer, there are several correct answers. Correct Go implementations can produce different results for this program. As I said above, different compilers behave differently today. It may happen that with the current Go 1.10 compiler the order is affected by whether you use an interface type, but future Go releases may well produce different results that are still completely valid.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
6 participants
You can’t perform that action at this time.