Scope of variable redeclarations

52 views
Skip to first unread message

Brian Candler

unread,
7:36 AM (12 hours ago) 7:36 AM
to golang-nuts
I'm having trouble understanding something in the go spec for short variable (re)declarations.  The spec says:

"redeclaration can only appear in a multi-variable short declaration. Redeclaration does not introduce a new variable; it just assigns a new value to the original."

It's that last sentence that I'm having problems squaring with observed behaviour.


package main

import "fmt"

func myfunc() (int, error) {
return 123, nil
}

func main() {
var code int
if code, err := myfunc(); err != nil {   // line 11
fmt.Printf("Error: %s", err)
return
}
fmt.Printf("code is %d", code)
}

This gives a compile error:

./prog.go:11:5: declared and not used: code

Adding a line to workaround this gives Example 2: https://go.dev/play/p/TVfTCc2bjAO

func main() {
var code int
if code, err := myfunc(); err != nil {
fmt.Printf("Error: %s", err)
_ = code
return
}
fmt.Printf("code is %d", code)
}

This prints 0, not 123.

These examples seem to show that the variable "code" (re)declared in the if-statement is a completely new variable which is local to the if block only.

(Aside: what I was actually trying to achieve is to tidy some program logic so that the "err" variable is local to the block - and hence can't accidentally be bound to later on in the function - whilst making the "code" value persist beyond the block where it can be used later)

Jan Mercl

unread,
7:52 AM (12 hours ago) 7:52 AM
to Brian Candler, golang-nuts
On Wed, Jan 14, 2026 at 1:36 PM 'Brian Candler' via golang-nuts
<golan...@googlegroups.com> wrote:

> I'm having trouble understanding something in the go spec for short variable (re)declarations. The spec says:

I believe the code is the equivalent of
https://go.dev/play/p/y96Q3YWjI-y. Which fails the same way, but IMO
not/less surprisingly, because the second 'code' variable is declared
in a different scope than the first one.

And it is a separate block because the specs says
(https://go.dev/ref/spec#Blocks)

""""
4. Each "if", "for", and "switch" statement is considered to be in its
own implicit block.
""""

-j

Def Ceb

unread,
7:53 AM (12 hours ago) 7:53 AM
to golang-nuts
This is a better example: https://go.dev/play/p/MRvbZLGB2Bi
If you now change the function signature to return (int32, error), then it will complain about a type mismatch.

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/golang-nuts/37978205-dafe-40e3-bf6d-f3f55aff7463n%40googlegroups.com.

Brian Candler

unread,
7:54 AM (12 hours ago) 7:54 AM
to golang-nuts
Hmm, but this prints 123:

func main() {
var code int
code, err := myfunc()
if err != nil {

fmt.Printf("Error: %s", err)
return
}
fmt.Printf("code is %d", code)
}

OK, so it must be to do with "if" declaring a new block scope:

"An identifier declared in a block may be redeclared in an inner block. While the identifier of the inner declaration is in scope, it denotes the entity declared by the inner declaration."

Brian Candler

unread,
8:53 AM (11 hours ago) 8:53 AM
to golang-nuts
OK, it's a block scope thing, because using an "if" statement I can also violate the rule that "at least one of the non-blank variables is new".

func main() {
var code int
var err error
if code, err := myfunc(); err != nil {  // this is accepted

fmt.Printf("Error: %s", err)
_ = code
return
}
fmt.Printf("code is %d, err is %v", code, err)  // 0, <nil>
}

So I need to imagine a curly bracket enclosing the whole 'if' statement.

Sorry for the noise.

Robert Engels

unread,
11:44 AM (8 hours ago) 11:44 AM
to Brian Candler, golang-nuts
Not noise. You highlight a very dumb rule of the syntax in my opinion. The mixing of new and old declarations with new variables possibly being introduced or old ones shadowed. 

I know it won’t/can’t change - but took the opportunity to rant :)

On Jan 14, 2026, at 7:54 AM, 'Brian Candler' via golang-nuts <golan...@googlegroups.com> wrote:

OK, it's a block scope thing, because using an "if" statement I can also violate the rule that "at least one of the non-blank variables is new".
--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.

Jan Mercl

unread,
11:48 AM (8 hours ago) 11:48 AM
to Robert Engels, Brian Candler, golang-nuts
On Wed, Jan 14, 2026 at 5:44 PM Robert Engels <ren...@ix.netcom.com> wrote:

> You highlight a very dumb rule of the syntax in my opinion. The mixing of new and old declarations with new variables possibly being introduced or old ones shadowed.

It's not dumb because it does not do what you wrote it does.

Robert Engels

unread,
12:10 PM (8 hours ago) 12:10 PM
to Jan Mercl, Brian Candler, golang-nuts
Yes it does. You can declare new variables while assigning to old in Go.

A very poor design choice imo.

> On Jan 14, 2026, at 10:47 AM, Jan Mercl <0xj...@gmail.com> wrote:

Jan Mercl

unread,
12:23 PM (7 hours ago) 12:23 PM
to Robert Engels, Brian Candler, golang-nuts
On Wed, Jan 14, 2026 at 6:09 PM Robert Engels <ren...@ix.netcom.com> wrote:

> Yes it does. You can declare new variables while assigning to old in Go.

No it does not AFAICT. You wrote:

""""
... mixing of new and old declarations with new variables possibly
being introduced or old ones shadowed.
""""

Please show a playground program where this happens. Note: shadowing
can happen only across blocks. The rules for short variable
declarations apply only within one block.

Caveat emptor: Go specs do not define the term "shadowing". So you may
be using a very different definition of shadowing than most other
people have in mind when talking about shadowing variables in Go.

Robert Engels

unread,
12:38 PM (7 hours ago) 12:38 PM
to Jan Mercl, Brian Candler, golang-nuts
Yes, I was using shadowing loosely.

When you have

var x int
… 100 lines of code …
x,y := somefunc()

And y is a new variable - you have no idea at the call site which is a new variable and which is not.

That is the “shadowing” I’m referring to - loosely in that it obscures what is actually happening at the call site. You need to know other context - breaking Go’s desire for explicitness.

> On Jan 14, 2026, at 11:23 AM, Jan Mercl <0xj...@gmail.com> wrote:
Reply all
Reply to author
Forward
0 new messages