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