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

Closed
zboya opened this issue May 28, 2018 · 13 comments
Closed
Labels
FrozenDueToAge NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Milestone

Comments

@zboya
Copy link

zboya 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
Copy link
Contributor

cznic 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
Copy link

DeedleFake 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
Copy link
Contributor

cznic commented May 28, 2018

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

@fraenkel
Copy link
Contributor

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

@cznic
Copy link
Contributor

cznic 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
Copy link
Contributor

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
@ianlancetaylor ianlancetaylor added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label May 28, 2018
@KISSMonX
Copy link

KISSMonX commented May 29, 2018

go1.10.2 darwin/amd64

image

@KISSMonX
Copy link

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
Copy link
Author

zboya commented May 29, 2018

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

@KISSMonX
Copy link

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

@ianlancetaylor
Copy link
Contributor

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.

@mdempsky
Copy link
Member

I'm closing this issue. The Go spec intentionally defines only a partial ordering on expression evaluation within a statement, and the behaviors demonstrated are all consistent with that (albeit admittedly surprising). So there's no action for us to take here.

I think we're open to defining a total ordering (e.g., like Java does and reportedly like C++ is considering), but that needs to take the form of a language spec proposal.

@mdempsky
Copy link
Member

See also #27804.

@golang golang locked and limited conversation to collaborators Oct 14, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Projects
None yet
Development

No branches or pull requests

8 participants