How Defer Works

Alexander Ibrahim
2 min readMay 2, 2020

Recently I had time to read about Effective go. And then I stumbled in defer section, I was wondering how come this code end up with this result

func trace(s string) string {
fmt.Println("entering:", s)
return s
}

func un(s string) {
fmt.Println("leaving:", s)
}

func a() {
defer un(trace("a"))
fmt.Println("in a")
}

func b() {
defer un(trace("b"))
fmt.Println("in b")
a()
}

func main() {
b()
}

and the result is

entering: b
in b
entering: a
in a
leaving: a
leaving: b

you can try it in golang playground

let us break down the flow behind the logic.

defer un(trace("b"))
fmt.Println("in b")
a()

The question is what function do we defer? un("b") or trace("b"), or both? It turn out that golang only defer un("b") function. That is why get get entering: b as the result and defer un("b") function. After that the application will run fmt.Println(“in b"). Next, It will execute a() function.

defer un(trace("a"))
fmt.Println("in a")

Same as the flow before, trace("a") will be executed first, and defer un("a") function. The result is entering: a. then fmt.Println("in a") will be run.

Now we have reach the end of application, we will take a look at defer function.

un("b")
un("a")

because of golang defer functions are executed in LIFO order, so un("a") will be exectuted first, and then un("b") the result as follow

leaving: a
leaving: b
The order of execution

--

--

Alexander Ibrahim
Alexander Ibrahim

Written by Alexander Ibrahim

A seasoned software engineer with 10+ years in designing and scaling high-performance systems. I love reading books on technology and beyond.

No responses yet