On 01/21/2013 09:27 PM, Jens Alfke wrote:
Yes, I do. If := always declared variables, you’d have a point. But
it doesn’t. If there are multiple variables in the LHS and some are
already declared in the current scope, they get reused.
OP's example, as well as this whole thread, has been about a very
specific case: declaring a variable through a short variable declaration
within a inner block, and in the process hiding a variable. This is the
case which has been discussed from the start of this thread. In this
case, the short variable declaration does not reuse the variable, and
instead declares a new entity. This is what has been discussed here, at
least until now. Hence, the post you've replied to.
With regards to the generic behavior of Go's short variable declaration,
you are right: if there are multiple variables and a subset of them has
been declared previously in the same block then the undeclared variables
will be declared and, as a convenient exception, the ones already
declared will be redeclared, "provided they were originally declared in
the same block with the same type"[1].
Yet, that is a convenient exception to the rule, but not the rule. If
any of those requirements isn't met then the code isn't valid, and the
compiler will throw an error. If the short variable declaration is used
without declaring a single variable (i.e., as a assignment operator)
then the code is broken and the compiler throws an error.
http://play.golang.org/p/y6vfSKvUykThat's because what the short variable declaration does is declare
variables, which in a very specific corner case also assigns a new value
to variables which have been declared previously. It is not an
assignment operator, which as a corner case also declares variables.
So, even when considering this corner case, the problem doesn't lie in
expecting that this way of declaring variables ends up declaring
variables, because that's not the exception to the rule but the rule itself.
So a
multi-value := statement can validly contain a mixture of declaration
and simple assignment. (And this mixture is very, very common in real
code due to the convention of returning errors as a second return
value, where the variable ‘err’ gets reused.)
This is true. Yet, again, it's an exception, which happens to be very
convenient. But just because, as an exception, this way of declaring
variables also supports a way to redeclare previously declared
variables, this doesn't mean that a short variable declaration is
actually an assignment operator. As I've pointed out previously, if a
short variable declaration is used in place of an assignment operator,
the compiler throws an error.
The argument being made here is that this can result in confusing
code where variables are shadowed unintentionally. Several people (in
this thread, and in my workplace) report running into this often
enough that it becomes a pain point in the language. In this case it
is not helpful to reiterate that the syntax is unambiguous — of
course it is, because a machine is parsing it. It’s easy to create
arbitrarily confusing and difficult-to-use syntaxes that are
nonetheless unambiguously parseable (brainf*ck is a fine example.)
My point was that, in the case presented by the OP, this is only
confusing due to a single misconception which can be easily understood.
More precisely, if we acknowledge that a variable declaration within a
inner block does declare a new variable and, in the process, hides any
variable declared previously that shares the identifier[2] then we won't
be surprised if that's what we get when we do precisely that. For
example, take the following examples:
<pseudosource>
var a int = 1
{
var a int = 0
fmt.Print(a)
}
fmt.Print(a)
</pseudosource>
<pseudosource>
var a int = 1
var a int = 0
</pseudosource>
If the first example isn't expected to triggers a compiler error while
the second one is expected to do so, and we understand why, then that's
more than enough to understand what happens with:
<pseudocode>
a := 1
{
a := 0
fmt.Print(a)
}
fmt.Println(a)
</pseudocode>
Is this confusing?
Rui Maciel
[1]
http://golang.org/ref/spec#Short_variable_declarations[2]
http://golang.org/ref/spec#Declarations_and_scope--