Why add "()" after closure body in Golang?

GoClosures

Go Problem Overview


I'm reading The Go Programming Language Specifications and found myself not truly understand with "()" after closure body:

In Function literals:

>func(ch chan int) { ch <- ACK }(replyChan)`

In Defer statements's example:

// f returns 1
func f() (result int) {
    defer func() {
	    result++
    }() // why and how?
	return 0
}

I'm not clear about the reason to add & usage of "()" after closure body, hope someone can explain this clearly.

Go Solutions


Solution 1 - Go

It's not that () must be added after (only) a closure in defer. The language specs for the defer statement mandate that its 'Expression' always must be a function call.

And why is it so? It's the same as with any other function, in 'defer' or not:

Consider:

func f() int { return 42 }

and

a := f

vs

b := f()

The first expression RHS is a function value. In the second version the RHS is the value returned by the function - i.e. a function call.

So is the semantics of:

defer f

vs

defer f()

except that the first version doesn't make sense in the context of 'defer', and so the specifications mention that it must be the second form (only).

It's IMHO also easier to learn because of the orthogonality with the above discussed function call outside of the 'defer' statement.

Also note that a function call is not only fn-expr followed by (), but an expression list is generally inside the parenthesis (including an empty list). There's a big difference between:

for i := range whatever {
        defer func() { fmt. Println(i) }()
}

and

for i := range whatever {
        defer func(n int) { fmt. Println(n) }(i)
}

The first version prints the value of 'i' in the moment when the closure executes, the second prints the value of 'i' in the moment when the defer statement was executed.

Solution 2 - Go

If you don't want to read long answers:

str := "Alice"
go func(name string) {
	fmt.Println("Your name is", name)
}(str)

Is same as:

str := "Alice"
f := func(name string) {
	fmt.Println("Your name is", name)
}
go f(str)

Solution 3 - Go

> References > > The Go Programming Language Specification > > Function types > > A function type denotes the set of all functions with the same > parameter and result types. > > FunctionType = "func" Signature . > Signature = Parameters [ Result ] . > Result = Parameters | Type . > Parameters = "(" [ ParameterList [ "," ] ] ")" . > ParameterList = ParameterDecl { "," ParameterDecl } . > ParameterDecl = [ IdentifierList ] [ "..." ] Type . > > Function declarations > > A function declaration binds an identifier, the function name, to a > function. > > FunctionDecl = "func" FunctionName Signature [ Body ] . > FunctionName = identifier . > Body = Block . > > Function literals > > A function literal represents an anonymous function. It consists of a > specification of the function type and a function body. > > FunctionLit = FunctionType Body . > > Function literals are closures: they may refer to variables defined in > a surrounding function. Those variables are then shared between the > surrounding function and the function literal, and they survive as > long as they are accessible. > > A function literal can be assigned to a variable or invoked directly. > > Calls > > Given an expression f of function type F, > > f(a1, a2, … an) > > calls f with arguments a1, a2, … an. > > In a function call, the function value and arguments are evaluated in > the usual order. After they are evaluated, the parameters of the call > are passed by value to the function and the called function begins > execution. The return parameters of the function are passed by value > back to the calling function when the function returns. > > Defer statements > > A "defer" statement invokes a function whose execution is deferred > to the moment the surrounding function returns. > > DeferStmt = "defer" Expression . > > The expression must be a function or method call. Each time the > "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 calls are executed in LIFO order > immediately before the surrounding function returns, after the return > values, if any, have been evaluated, but before they are returned to > the caller.

Since you are still confused, here's another attempt to provide an answer to your question.

In the context of your question, () is the function invocation operator.

For example, the function literal

func(i int) int { return 42 * i }

represents an anonymous function.

The function literal followed by the () function invocation operator

func(i int) int { return 42 * i }(7)

represents an anonymous function which is then invoked directly.

Ordinarily, in a function call, the function value and arguments are evaluated in the usual order. After they are evaluated, the parameters of the call are passed by value to the function and the called function begins execution. The return parameters of the function are passed by value back to the calling function when the function returns.

However, invoking the function through the defer statement is a special case. Each time the "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 calls are executed in LIFO order immediately before the surrounding function returns, after the return values, if any, have been evaluated, but before they are returned to the caller.

The defer statement expression must be a function or method call that is invoked directly, not just a function or method literal which is not invoked directly. Therefore, the function or method literal needs to be followed by the () function invocation operator so that the defer statement expression is a function or method call.

The defer statement

defer func(i int) int { return 42 * i }(7)

is valid.

The defer statement

defer func(i int) int { return 42 * i }

is invalid: syntax error: argument to go/defer must be function call.

Solution 4 - Go

Without the (), you are not executing the function.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionReck HouView Question on Stackoverflow
Solution 1 - GozzzzView Answer on Stackoverflow
Solution 2 - GoErikasView Answer on Stackoverflow
Solution 3 - GopeterSOView Answer on Stackoverflow
Solution 4 - GoPatView Answer on Stackoverflow