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: clarify order in which operands of multi-value assignments are evaluated #27821

Open
go101 opened this Issue Sep 23, 2018 · 1 comment

Comments

Projects
None yet
3 participants
@go101

go101 commented Sep 23, 2018

(This issue is separated from #27804 after I realized it is not a proposal but just a doc improvement. There are no language changes in the improvement.)

Currently, for assignments in Go, Go specification specifies

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 rule description is some ambiguous. It doesn't specify clearly how the operands in the mentioned expressions on the left should be exactly evaluated. This is the cause of some disputes.

For the following program, if it is compiled with gccgo (version 8), then it will panic. But if it is compiled with the standard Go compiler, then the program will exit without panicking.

package main

func main() {
	s := []int{1, 2, 3}
	s, s[2] = []int{1}, 9 // gccgo 8 think s[2] is index of range
}

Obviously, gccgo think the multi-value assignment is equivalent to

	s = []int{1}
	s[2] = 9

However, the standard Go thinks it is equivalent to

	tmp1 = &s
	tmp2 = &s[2]
	*tmp1, *tmp2 = []int{1}, 9

Most Go team members think the interpretation of the standard Go compiler is what Go specification wants to express. I also hold this opinion.

To avoid description ambiguities, it would be good to append the following description to the rule.

In the first phase, if the map value in a destination expression is not addressable, the map value will be saved in and replaced by a temporary map value. Just before the second phase is carried out, each destination expression on the left will be further evaluated as its elementary form. Different destination expressions have different elementary forms:

  • If a destination expression is a blank identifier, then its elementary form is still a blank identifier.
  • If a destination expression is a map index expression m[k] then its elementary form is (*maddr)[k], where maddr is the address of m.
  • For other cases, the destination expression must be addressable, then its elementary form is a dereference to its address.

I think these supplement descriptions can avoid the above mentioned disputes.

@ianlancetaylor

This comment has been minimized.

Contributor

ianlancetaylor commented Sep 24, 2018

For what it's worth, tip gccgo behaves like gc. See #23188.

@ianlancetaylor ianlancetaylor added this to the Go1.12 milestone Sep 24, 2018

@griesemer griesemer changed the title from spec: clarify how should the operands invloved in multi-value assignments be evaluated. to spec: clarify order in which operands of multi-value assignments are evaluated Sep 24, 2018

@griesemer griesemer modified the milestones: Go1.12, Go1.13 Dec 11, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment