Immediately Invoked Function Expressions

This is a quite frequent code pattern: An anonymous function that is defined and immediately invoked as a goroutine.

go func() {
	//...
}()

This is possible because functions in Go can be expressions. The following two function definitions are equivalent:

func f() int {return 2}

g := func() int {return 4}

The second function definition is an expression at the right-hand side of an assignment. The function can be called like a “normal” function: n := g().

I guess you already have an idea where this is going to. Yes, you can combine a function expression and the immediate invocation pattern from the goroutine to form an Immediately Invoked Function Expression (IIFE):

n := func() int {return 8}()

What would that be good for? Here are some use cases and situation where IIFE can be advantageous:

  • Complex variable initialization at startup. For example, you might need to initialize a variable with a random value, and this initialization requires more than an call to math/rand or crypto/rand.
  • No need for using a frowned-upon func init() in your modules.
  • Avoid polluting a module's function namespace with names of one-time functions. Keep function definitions inside the minimal possible scope of usage.

But don't overuse this pattern. While it may be useful in certain situations, it has a drawback. Compare these two lines:

g := func() int {return 4}

n := func() int {return 8}()

From a quick glance, it is hard to tell the difference. Two innocent-looking parentheses at the very end of the line completely change the result of the assignment. g is a func waiting to be called, whereas n is the result of a function that has been called already.

Put that pattern into the category “clever”, and remember the Go proverb:

Clear is better than clever.