How does defer and named return value work?

Go

Go Problem Overview


I just started learning Go and I got confused with one example about using defer to change named return value in the The Go Blog - Defer, Panic, and Recover.

The example says:

>3. Deferred functions may read and assign to the returning function's named return values. > >In this example, a deferred function increments the return value i after the surrounding function returns. Thus, this function returns 2:

func c() (i int) {
    defer func() { i++ }()
    return 1
}

But as what I have learned from A Tour of Go - Named return values

>A return statement without arguments returns the named return values. This is known as a "naked" return.

I tested in the following code and in function b it returns 1 because it wasn't the "A return statement without arguments" case mentioned above.

func a() (i int) { // return 2
    i = 2
    return
}

func b() (i int) {  // return 1 
    i = 2
    return 1
}

So my question is in the first example, the surrounding function c has a named return value i, but the function c uses return 1 which in the second example we can see it should have return 1 no matter what value i is. But why after i changes in the deferred function the c function returns the value of i instead the value 1?

As I was typing my question, I might have guessed the answer. Is it because:

return 1 

is equals to:

i = 1
return 

in a function with a named return value variable i?

Please help me confirm, thanks!

Go Solutions


Solution 1 - Go

> A defer statement pushes a function call onto a list. The list of saved calls is executed after the surrounding function returns. -- The Go Blog: Defer, Panic, and Recover

Another way to understand the above statement:

>A defer statements pushes a function call onto a stack. The stack of saved calls popped out (LIFO) and deferred functions are invoked immediately before the surrounding function returns.

 func c() (i int) {
    defer func() { i++ }()
    return 1
}

After 1 is returned, the defer func() { i++ }() gets executed. Hence, in order of executions:

  1. i = 1 (return 1)
  2. i++ (defer func pop out from stack and executed)
  3. i == 2 (final result of named variable i)

For understanding sake:

 func c() (i int) {
    defer func() { fmt.Println("third") }()
    defer func() { fmt.Println("second") }()
    defer func() { fmt.Println("first") }()

    return 1
}

Order of executions:

  1. i = 1 (return 1)
  2. "first"
  3. "second"
  4. "third"

Solution 2 - Go

According to the Go Specification:

Return Statements A "return" statement that specifies results sets the result parameters before any deferred functions are executed.

Defer Statements "...deferred functions are invoked immediately before the surrounding function returns..."

So yes, as you assumed, the named return variable is assigned, then the deferred statement increments it.

I would add that named return parameters can lead to subtle bugs, and generally should be avoided unless there's no alternative.

Solution 3 - Go

I think the confusion is about function in function how about if you classified like this:

  func main() {
      fmt.Println(c()) //the result is 5
  }
  
  // the c function returned value is named j
  func c() (j int)  {
      defer changei(&j)
      return 6
  }
  func changei(j *int) {
      //now j is 6 because it was assigned by return statement 
      // and if i change guess what?! i changed the returned value
      *j--;
  }

but if the return value is not named like this:

  func main() {
      fmt.Println(c()) //the result will become 6
  }

  // the c function returned value is not named at this time
  func c() int  {
      j := 1
      defer changei(&j)
      return 6
  }
  func changei(j *int) {
      //now j = 1
      // and if i change guess what?! it will not effects the returned value
      *j--;
  }

I hope this will clear the confusion and that is how i did happy Go coding

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionLutionView Question on Stackoverflow
Solution 1 - GoRoy LeeView Answer on Stackoverflow
Solution 2 - GoMarkView Answer on Stackoverflow
Solution 3 - GoAhmed OzmaanView Answer on Stackoverflow