2

This is a function in Golang that uses defer to alter the named return value of the function c().

package main

import "fmt"

func c() (i int) { 
    defer func() {  }()     
    defer fmt.Println("our i is", i)
    return 45
   }

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

The output of the program is:

our i is 0

45

changing the anonymous func() in the code

func c() (i int) { 
        defer func() { i = 1 }()   
        defer fmt.Println("our i is", i)
        return 45
       }

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

This results in the output:

our i is 0

1

It seems like the return value 45 is copied to i automatically if no other value is being put inside i. But I am not a 100% sure if that is the exact reason for the output

Aditya Sanghi
  • 289
  • 1
  • 3
  • 18

1 Answers1

2

In deferred functions you have the opportunity to modify the values of the result parameters.

When deferred functions are called, values specified in the return statement are already set.

If there are multiple deferred functions, they are executed in LIFO order (last in, first out).

In your second example fmt.Println() is executed first, then the other, anonymous function.

But what you need to know that when the defer statement is executed, the arguments to the deferred function are evaluated immediately, not when the deferred function will be run (later, before returning).

Spec: Defer statements:

Each time a "defer" statement executes, the function value and parameters to the call are evaluated as usual and saved anew but the actual function is not invoked. Instead, deferred functions are invoked immediately before the surrounding function returns, in the reverse order they were deferred.

So this line:

defer fmt.Println("our i is", i)

Will always mean to call fmt.Println() with i = 0 argument:

fmt.Println("our i is", 0)

Because when this line runs, i has a value of 0.

So in your 2nd example fmt.Println() prints 0, then runs the other deferred function which sets i to 1 and this is what is returned.

Your first example just prints something (i = 0), but the deferred functions in the first example do not modify the value of i so 45 will be returned (and printed by the fmt.Println() function from the main()).

Please see the following questions/answer for more on the topic:

Defer usage clarification

How to return a value in a Go function that panics?

Community
  • 1
  • 1
icza
  • 389,944
  • 63
  • 907
  • 827
  • reversing the order of the defer statements also gives the exact same output. Another thing is that why is the constant 45 outputted the first time but not in the second case? – Aditya Sanghi Oct 19 '15 at 11:08
  • @AdityaSanghi The `45` is outputted by the `fmt.Println()` statement in the **`main()`** function, not by the `Println()` in the `c()` function. `45` is returned from `c()`, that's why. – icza Oct 19 '15 at 11:12
  • But why is it returning 1 when I explicitly modify i (in the second code example). Basically I am not clear about why the return values are behaving differently in the 2 code examples. – Aditya Sanghi Oct 19 '15 at 11:14
  • @AdityaSanghi In your first example, deferred functions don't modify `i`, so `45` is returned (from `return 45`). In your second example a deferred function modifies `i` to `1`, so `1` will be returned. – icza Oct 19 '15 at 11:16
  • so does modifying the i cause it to take priority as the return value? – Aditya Sanghi Oct 19 '15 at 11:18
  • @AdityaSanghi Yes, deferred functions are run **after** the values specified in the `return` statement are set. – icza Oct 19 '15 at 11:19
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/92718/discussion-between-aditya-sanghi-and-icza). – Aditya Sanghi Oct 19 '15 at 11:20
  • @AdityaSanghi I don't have access to chat here. Just think it through. I think you have all the info to understand it now. – icza Oct 19 '15 at 11:22
  • The only small doubt remaining is that shouldnt the function c() always look for the value of named return value **i** and return that even if **i** is not being modified – Aditya Sanghi Oct 19 '15 at 11:24
  • @AdityaSanghi I don't understand your question. `i` will be set to the value specified in the `return` statement. This may be optionally modified _after_ in the deferred functions. The value `i` holds after running the deferred functions will be the value returned from `c()`. – icza Oct 19 '15 at 11:26
  • thankyou so much. so basically in the first example, 45 was implicitly being stored in i and returned as such. – Aditya Sanghi Oct 19 '15 at 11:30
  • 1
    @AdityaSanghi Yes. It was also stored in the 2nd example, but then it was changed to `1`, so `1` was returned. – icza Oct 19 '15 at 11:33