Higher Order Functions (HOF)

We can pass functions as data to another function.

A function that takes in another function as a parameter or returns another function is called a Higher-order function.

func aggregate(a, b, c int, arithmetic func(int, int) int) int {
    return arithmetic(arithmetic(a, b), c)
}

The aggregate () function takes four parameters. As you can see, the last one is another function. And the aggregate () function calls the passed-in function twice and returns an int.

First Class Function (FCF)

  • A function that is treated like another variable.

HOFs and FCFs are usually used as,

  • HTTP API handlers
  • pub/sub handlers
  • onclick handlers

Currying

  • Writing a function that takes function/s as parameters and returns a new function.
  • It is not very commonly used in programming.
// Takes two integers and returns their product
func multiply(x, y int) int {
    return x * y
}

func doMath(mathFunc func(int, int) int) func (int) int {
    return func(x int) int {
        return mathFunc(x, x)
    }
}

func main() {
    squareFunc := doMath(multiply) // Pass the multiply function to doMath
    fmt.Print(squareFunc(5))
}

In the above example, square(5) internally does doMath(multiply(5, 5)). So the final answer is 25. Here we have wrapped multiply inside a new function that always multiplies a number by itself.

Defer

  • A keyword unique to Go.
  • Allow a function to execute automatically right before its enclosing function returns.

Why is this defer() required? Check the example below. The copyFile function has several return statements. When you open a file, you should close it once its usage is done. But you have done it before every return statement. This is tedious. So instead, you can use a defer.

func copyFile(desination, source string) (written int64, err error) {
    src, err := os.Open(source) // open file
    if err != nil { return }

    defer src.Close()

    dest, err := os.Create(desination) // create file
    if err != nil { return }

    defer dest.Close()

    return io.Copy(dest, src) // copy source file content to dest file
}

Closures

  • Functions that reference variables that are outside their function bodies.
  • They may also access and assign to the referenced variables.
// closure function
func counter() func() int {
    count := 0
    return func() int {
        count++
        return count
    }
}

func main() {
    c := counter()

    fmt.Println(c()) // 1
    fmt.Println(c()) // 2
    fmt.Println(c()) // 3

    d := counter()   // new counter
    fmt.Println(d()) // 1
}

In the above example, the count variable in counter() is outside of the function body of its return function. But whenever you call c (in the main function) again and again, the reference to the count is increased.

Anonymous functions

  • Functions with no names
  • used in closures or when you return a function as a return value.

Check the example below.

func main() {
    // Anonymous function assigned to a variable
    greet := func(name string) string {
        return "Hello, " + name
    }

    // Call the anonymous function
    message := greet("Edward Cullen")
    fmt.Println(message)
}

The above example will print Hello, Edward Cullen