Can you do that later Please, but don’t forget it, its important

Follow the latest of Whizdumb’s journey here.

We all have been in a situation in real life, where we need to get a thing done, which needs to be done by the end of a day or by the end of some time frame. You can not afford to forget it or delay it any longer. Think going into production on Friday!, you want to done over with it on Friday itself and not take it over to the weekend!

Such situations happen in programming too, where you need to get a thing done, you can delay it to later but it must be done under all circumstances.

Think of closing those open connections to database, which need to be closed even if an exception occurs. You can afford to close them at some later time, but they must be closed.

In java we do that in finally block.

In comes the defer in go-lang. Defer delays the statement to be executed till the end of the function and ensures that the deferred statement is executed.

Lets understand it in Detail

Consider the following code

package main
import "fmt"

func main() {   
    x := 1    
    defer fmt.Println ("The value of x is ", x)
    x = 10
    defer fmt.Println ("The updated value of x is ", x)
}

In this we have deferred both our Print calls. Defer calls act like a stack, so in this case the last deferred call will be executed first and then the first call.

So we will see “The updated value of x is ” before “The value of x is “. Here is the output

The updated value of x is  10
The value of x is  1

Notice that even though the value of x has been updated to 10, the deferred call still takes the value as 1, which would have been the output had the call not been deferred!

But does it ensure that our deferred calls are always executed even if there is an unexpected situation occurring. Lets check it.

package main
import "fmt"
func main() {   
    x := 1    
    fmt.Println("Everything is good")
    defer fmt.Println ("The value of x is ", x)
    x = 10
    fmt.Println("Panic is going to occur now!!")
    panic("Lord Voldemort has returned!!")
    fmt.Println("Panic has occured!")
    defer fmt.Println ("The updated value of x is ", x)
}

In the above code we have a panic statement, there is a defer before the panic and a defer after the panic. Lets look at the output

Everything is good
Panic is going to occur now!!
The value of x is  1
panic: Lord Voldemort has returned!!

goroutine 16 [running]:
runtime.panic(0xfc0c0, 0x1030e0f8)
	/tmp/sandbox/go/src/pkg/runtime/panic.c:279 +0x120
main.main()
	/tmpfs/gosandbox-e65a337d_cc5e9f3f_1ba937ab_6eecf9d9_0feba4c1/prog.go:10 +0x320

goroutine 19 [runnable]:
runfinq()
	/tmp/sandbox/go/src/pkg/runtime/mgc0.c:2606
runtime.goexit()
	/tmp/sandbox/go/src/pkg/runtime/proc.c:1445
 [process exited with non-zero status]

In the output we can see that first defer statement which ideally should have been printed in the last has been printed whereas print statements after the panic have not been printed.
Indeed the last deferred statement has not been printed because the runtime never got there.

We should always write deferred statements which must be executed as early as we possibly can to reduce their chances of not being run like the last deferred statement.

Thing to note is defer is a function level construct. Deferred statements execute as the last statements before the function returns.

Later!

~~ Whizdumb ~~