$Search: Defer pitfalls

When using defer keep the following in mind: deferred functions are called at the end of a function.

Deferred statements have a function scope, not a block scope.

In other words: deferred calls are executed when exiting a function not when executing block created with if or for statements.

https://codeeval.dev/gist/6550d53e2a0b05e2ae6097b3a5bb62ef

You might expect that deferred statement to be executed when we exit if branch but it’s executed as the last thing in a function.

Using outside variables in defer functions

https://codeeval.dev/gist/8ddf998e7edb105cc3e0255c6711d89a

A common mistake is to think that this code will print 0 and 1. Those are the values of i when we see defer.

However, defer creates a closure which only captures variable i by a reference. It doesn't capture the value of the variable.

It should be become clear when we look at what code executes:

var i int
for i = 0; i < 2; i++ {
	// create closure that references i by reference
}

fmt.Printf("%d\\n", i) // from created by defer in second loop iteration (remember: reverse order)
fmt.Printf("%d\\n", i) // from closure created by defer in first loop iteration

Now it’s clear that when we call deferred fmt.Printf, i is 2.

We can fix this by forcing a capture of the variable:

https://codeeval.dev/gist/8eeb536e05f82db13271ae0df6ce9272

A closure might be slightly more expensive as it requires allocating an object to collect all the variables captured by the closure.