Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The deferred call's arguments are evaluated immediately

Tags:

go

deferred

In A Tour of Go is written:

The deferred call's arguments are evaluated immediately, but the function call is not executed until the surrounding function returns.

I have difficulty in understanding the first part of the quote. What is called immediately?

func def(s string) func() {
    fmt.Println("tier up")
    fmt.Println(s)
    return func(){ fmt.Println("clean up") }
}

func main() {
    defer def("defered line")()
    fmt.Println("main")
}

//Output:
//tier up
//defered line
//main
//clean up

https://play.golang.org/p/Av3mAEXxA4R

What is deferred here and what is evaluated immediately?

like image 958
Rudziankoŭ Avatar asked Mar 05 '23 19:03

Rudziankoŭ


1 Answers

To learn how defer and evaluations work, first let's look at the 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.

Both the function value (whose call is deferred) and its parameters are evaluated. But the deferred function is not yet called.

Let's iterate toward your example with small steps:

defer f("a")

In this case the function value is evaluated (which will be f), and the parameters are evaluated, which is a constant, so that's gonna be "a".

Next step:

defer f(g("a"))

In this case the function value is evaluated (which will be f), and the parameters are evaluated, which means g will be called with "a" (because g's return value is the param to f).

Next step:

defer f()()

This is valid if the f function returns a function. The function value will be evaluated (which means f will be called!) but its return value will not be called, that is what will be deferred.

defer f(g())()

In this case the deferred function is the return value of f, so to evaluate the deferred function value, f must be called, and to do that g must be called prior. The return value of f will be deferred (not called).

Back to your example:

defer def("defered line")()

The function value is evaluated, which is the return value of def, so def is called. The return value of def will be deferred. Its parameters are evaluated, but actually it has no parameters.

So logically this is what happens:

  1. The deferred function value is evaluated, which requires that:
    • def function must be called, which requires that:
      • Params to def are evaluated, it's a constant: "defered line"
  2. Parameters to the deferred function are evaluated; since there are no params to it, this step is done.

This is what happens sequentially if we lay out the above structure:

  • Param to def is evaluated: it's a constant "defered line"
  • def is called which prints tier up and its argument: defered line
  • The return value of def is not called, that is what's deferred.
  • Function main prints: main
  • Function main returns, so deferred functions are called now. The deferred function prints clean up
like image 90
icza Avatar answered Mar 09 '23 07:03

icza