# Defer execution order

### August 26, 2024

Let’s talk about some of the nuance surrounding `defer` that’s often lost, or simply forgotten.

### 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. That is, if the surrounding function returns through an explicit return statement, deferred functions are executed after any result parameters are set by that return statement but before the function returns to its caller. If a deferred function value evaluates to `nil`, execution panics when the function is invoked, not when the “defer” statement is executed.

Let’s take this point by point.

When execution encounters a `defer`red function:

“function value and parameters are evaluated as usual” … “but the actual function is not invoked”

This bites all of us when we’re learning. And some of us it continues to bite for years into the future!

But what does it mean, exactly?

Let’s illustrate with an example.

``````func foo() {
var i int
defer fmt.Println(i)
i = 10
fmt.Println("foo")
}
``````

What do you think this code will print when executed?

Try it if you like, to see that it prints:

``````foo
0
``````

Does this surprise you?

The arguments to the deferred `fmt.Println` function are evaluated at the time the `defer` is encountered during execution, and at that point `i == 0`… but the function itself isn’t executed until the surrounding `foo` function returns, so after `foo` is printed.

Now, what do you think this will print?

``````func foo() {
var i int
defer func(p *int) { fmt.Println(*p) }(&i)
i = 10
fmt.Println("foo")
}
``````

In this case, we’re passing a pointer to `i` to the deferred function. The argument is still evaluated immediately, as before… but in this case, when `foo` exits and the anonymous deferred function is executed, the value pointed to by `i` has changed, and we get the following output:

``````foo
10
``````

The function to be deferred is also evaluated immediately, not upon function exit. To demonstrate:

``````func main() {
defer bar()()
fmt.Println("Hello, 世界")
}

func bar() func() {
fmt.Println("a")
return func() {
fmt.Println("b")
}
}
``````

This will output the following:

``````a
Hello, 世界
b
``````

And the final point: If the function being deferred evaluates to `nil`, it will panic, but after the function returns, not at the point that `defer` is encountered:

``````func main() {
defer bar()()
fmt.Println("Hello, 世界")
}

func bar() func() {
fmt.Println("a")
return nil
}
``````

This code will panic after some output:

``````a
Hello, 世界
panic: runtime error: invalid memory address or nil pointer dereference
``````

See for yourself

Quotes from The Go Programming Language Specification Language version go1.23 (June 13, 2024)