It is best illustrated with the following Go code snippet.
var x int
x, y := 1, 2 // x declared above is set to 1, y is declared and set to 2
if true {
x, z := 3, 4 // declare a local x and z, and set them to 3 and 4. This x shadows the x declared above.
}
The trap is that the x in the if blocks is a new local variable that shadows the x variable declared in the enclosing block.
-
While constraining, the use of
:=
should not allow predefied variables in the lefthand side of:=
. This would remove any ambiguity. Unfortunately, this is not backward compatible and might break a lot of code. It is however my preferred solution because it removes all ambiguity on variable declaration and shadowing. It would be a short hand ofvar x, y = 1, 2
. -
A compiler warning should be issued when a variable on the lefthand side of
:=
might shadow a variable defined in the enclosing context. It would be backward compatible. But a lot of existing code would issue compiilation warnings. -
Dissalow the
:=
notation. I had to suggest it for completeness, but this would break even more code and piss off a lot of people. Don't even think of it. ;)
It is best illustrated with the following Go code snippet.
var x
x, y := 1, 2 // ok
var a struct{b int}
a.b, c := 1, 2 // compilation error: "expected identifier on left side of :=" or "non-name a.b on left side of :="
This appears inconsistent. Why is x
allowed and not a.b
? Both are predefined variables.
Even the compilation error message appears inconsistent. With the above code, the compilation error message is "expected identifier on left side of :=". If we remove the var x
and x, y := 1, 2
lines, the compilation error message becomes "non-name a.b on left side of :=".
-
Disallow use of any predefined variables on the lefthand side of
:=
. Any varible on the lefthand side of:=
would be declared at that spot. It's my preferred solution. See comment above. -
Allow use of
a.b
as any other predefined variables. There is no risk of shadow variable trap with this change. It would be backward compatible.
Note: published in "Golang experience report"
I encountered this problem for the first time when dealing with a function that returned an error and a value that was to be set as global. While the specific problem may be solved by upcoming error changes, it still exists as a problem for multi returns.
I feel that something that needs to be considered as a solution to the shadowing problem would be to disallow shadowing completely. As far as I am aware, it is bad practice to have shadowing in code to begin with as it is easy to create confusion on what variable is being used. Though it would have a problem with backwards compatibility, most problem code would benefit from having different variable names in different scopes.