Stratus3D

Software Engineering, Web Development and 3D Graphics

Variable Hoisting in Golang

I had the opportunity to work with the Go programming language about a month ago. Since I prefer functional programming over object oriented programming I wanted to see if I could create things like closures and first class functions. It turns out all of this is possible in Go. In this post we will write a function that takes function as one of its arguments and invokes the function on every element of an array (much like the map function). Then we will create a closure by defining a function within a function and use the closure to hoist a variable up into scope of the parent function. In the end we can combine the two functions into some code that computes the sum of all numbers in an array. The code in this post is meant to showcase Go’s closures and first class functions. There are much easier ways of summing the values of all the numbers in an array than this. If you need the sum of all the numbers in an array just write a for loop that adds each of the numbers to a sum variable one by one.

The since the first function takes another function and applies it to each item in an array we will can call it ApplyToArray. The complete function is below:

func ApplyToArray(fun func(int) error, numbers []int) (err error) {
  for i := 0; i < len(numbers); i++ {
    err := fun(numbers[i])
    if err != nil {
      return err
    }
  }
  return nil
}

The first thing to note about this function are the arguments that it expects. The first argument must be a function that takes an integer and returns an error (fun func(int) error) and second is an array of integers. The function that is passed in is bound to the fun variable in the function. The body of the functions is simply a for loop that iterates over all the numbers in the numbers array. Inside the for loop the function that was passed in (fun) is invoked on each number. Since the return value is an error we check to see if the error is nil. If the error is not nil we stop iteration and return the error. Otherwise the loop continues. This allows us to pass any function in and have it invoked with each element in the array, but due to Go’s strongly typed nature it limits what the array can contain and what types function passed in must receive and return. The ApplyToarray function above will only be able to handle a function that expects an integer and an array containing integers as arguments. Anything else will raise an exception.

Now that we have our ApplyToArray function complete let’s build a function that computes the sum of all the values in an array. As you probably noticed the ApplyToArray function invokes the given function with every element in the array, but it doesn’t provide a way for the function that is passed in (sum) to return an intermediate value and pass it to the next invocation of the sum function. We can easily get around this by using a closure to “hoist” the variable out to the sum function we pass into the ApplyToArray function. We will call this new function Sum. Here is the complete Sum function:

func Sum(numbers []int) (sum int) {
  sum = 0
  fun := func(number int) (err error) {
    sum = sum + number
    return nil
  }
  ApplyToArray(fun, numbers)
  return sum
}

Inside Sum we set the sum variable to 0 and then create a function and assign it to the variable fun. fun expects an integer as it’s only argument, so it matches the type specified for the first argument of ApplyToArray. Inside fun is where things get more interesting. We take the number passed in and add it to the sum variable. Then we assign the result of the addition back to the sum variable. But the sum variable is not defined inside fun. It is defined outside fun in the Sum function. Since the variable sum is not defined inside fun we are actually referencing the sum variable defined in the Sum function scope. The fun function we defined inherited the scope of its parent function and that allows us to make changes to sum from inside fun. This means that if we were to invoke fun with the integer 1 the value of the sum variable inside the Sum function would equal 1 as well. This is variable hoisting.

After defining the fun function in Sum we invoke ApplyToArray with fun and the array of numbers. Once ApplyToArray returns the sum variable contains the sum of all the integers in the numbers array, which we simply return to the caller of the function.

The complete example code using both functions looks like this:

package main

import "fmt"

func main() {
  sum := Sum(numbers)
  fmt.Println(sum)
}

func Sum(numbers []int) (sum int) {
  sum = 0
  fun := func(number int) (err error) {
    sum = sum + number
    return nil
  }
  ApplyToArray(fun, numbers)
  return sum
}

func ApplyToArray(fun func(int) error, numbers []int) (err error) {
  for i := 0; i < len(numbers); i++ {
    err := fun(numbers[i])
    if err != nil {
      return err
    }
  }
  return nil
}

It’s nice to see that see things like first class functions are present in a newer compiled language like Go. While I don’t think I will be using Go very often on projects in the future I enjoyed learning it and it was definitely worth it. Check it out at golang.org.

If you have any questions feel free to email me.