golang/go

Returned variable behaves differently with defer when included in argument signature

Closed this issue · 1 comments

tdarci commented

Go version

go 1.25 from go.dev/play

Output of go env in your module/workspace:

used go.dev/play

What did you do?

I have a function with a named return argument.
The value of that argument gets changed inside a defer.
The value returned by the function is what it was set to inside the defer.
However, if I remove the named argument from the function's signature, and declare it inside the function instead, the value returned does NOT reflect the change made inside the defer.

Is this expected?
It surprised me. I was expecting both versions to behave the same.
My guess is it's some subtlety about the scope of variables defined in function signatures. Would love to understand.

go playground link here:
https://go.dev/play/p/waiJQWK7k_F

What did you see happen?

program:

package main

import (
	"fmt"
)

func main() {
	fmt.Println(a())
	fmt.Println(b())
	fmt.Println(c())
}

func a() (out string) {
	out = "SET IN FUNCTION BODY: variable declared in signature. returned explicitly."
	defer func() {
		out = "SET IN DEFER: variable declared in signature. returned explicitly."
	}()
	return out
}

func b() (out string) {
	out = "SET IN FUNCTION BODY: variable declared in signature. returned implicitly."
	defer func() {
		out = "SET IN DEFER: variable declared in signature. returned implicitly."
	}()
	return
}

func c() string {
	out := "SET IN FUNCTION BODY: variable declared inside function."
	defer func() {
		out = "SET IN DEFER: variable declared inside function."
	}()
	return out
}

output:

SET IN DEFER: variable declared in signature. returned explicitly.
SET IN DEFER: variable declared in signature. returned implicitly.
SET IN FUNCTION BODY: variable declared inside function.

What did you expect to see?

I expected consistency. So either this:

SET IN DEFER: variable declared in signature. returned explicitly.
SET IN DEFER: variable declared in signature. returned implicitly.
SET IN DEFER: variable declared inside function.

or this:

SET IN FUNCTION BODY: variable declared in signature. returned explicitly.
SET IN FUNCTION BODY: variable declared in signature. returned implicitly.
SET IN FUNCTION BODY: variable declared inside function.

Working as intended.

Unlike many projects, the Go project does not use GitHub Issues for general discussion or asking questions. GitHub Issues are used for tracking bugs and proposals only.

For questions please refer to https://github.com/golang/go/wiki/Questions