Possible shadowing bug in named return variables?

152 views
Skip to first unread message

Mike Schinkel

unread,
Sep 7, 2025, 11:09:42 PM (5 days ago) Sep 7
to GoLang Nuts Mailing List
Hi Gophers,

I have some code that is not working as I expect it to and wanted to see if I was misunderstanding something or if there is in fact a bug in the compiler. I have tried this in v1.24.5 and 1.25.1.

Here is a version of the code — heavily cut down to provide a minimal example — that is not acting as I expect it to:
func ensureRootConfig(cs cfgutil.ConfigStore) (root *RootConfigV1, err error) {
if cs != nil {
root = &RootConfigV1{}
err = cs.LoadJSON(&root)
} else {
root = NewRootConfigV1(RootConfigV1Args{})
err = cs.SaveJSON(root)
}
return root, err
}
When I run the above code the assignment to `root` gets shadowed and the return variable is null. I have confirmed this using Goland and the Delve debugger.

The following does not shadow `root`:
func ensureRootConfig(cs cfgutil.ConfigStore) (*RootConfigV1, error) {
var root *RootConfigV1
var err error
if cs != nil {
root = &RootConfigV1{}
err = cs.LoadJSON(&root)
} else {
root = NewRootConfigV1(RootConfigV1Args{})
err = cs.SaveJSON(root)
}
return root, err
}

This code, of course also works, too, but with multiple returns is not the style of code we want use:
func ensureRootConfig(cs cfgutil.ConfigStore) (*RootConfigV1, error) {
if cs != nil {
root := &RootConfigV1{}
err := cs.LoadJSON(&root)
return root, err
}
root := NewRootConfigV1(RootConfigV1Args{})
err := cs.SaveJSON(root)
return root, err
}

I do understand that some might want to say “just use the other approaches” but if this is a bug it still needs to be reported and ideally fixed given how the language should allow this, right?  That is unless I misunderstand something about how named return variables work with shadowing.

-Mike


Mike Schinkel

unread,
Sep 8, 2025, 12:21:06 AM (5 days ago) Sep 8
to golang-nuts
Hi Gophers again,

I am noticing that there is a bug in own code in my email example that did not exist in my real world code (e.g. calling SaveJSON() on a nil `cs`; my real world code called !cs.Exists() instead.)

Anyway, going back to my real world code I can no longer reproduce the shadowing behavior that caused the failure that I believed I had seen before. GoLand+Delve DOES still report the variable as being shadowed but when the variable is assigned it updates BOTH the "shadowed" version and the regular version of the variable in the watch window. So this might just be a bug in either Goland and/or Delve.

As such, I believe this was not a bug in the Go compiler.  Sorry for the false alarm.

-Mike

TheDiveO

unread,
Sep 8, 2025, 12:10:43 PM (5 days ago) Sep 8
to golang-nuts
There is no shadowing, this is a Golang reporting bug.

TheDiveO

unread,
Sep 8, 2025, 4:01:01 PM (5 days ago) Sep 8
to golang-nuts
"Goland bug", not Golang.
Reply all
Reply to author
Forward
0 new messages