Closures and How We Can Use Them

Jul 21st 2020

By Robert Kirchner JR


Pacman

In this article we talk about what closures are and how they can be used.

The examples in this article will be written in Scala.

First Class Functions

A programming language that supports first class functions, allows you to pass functions as arguments, and also return functions as a result of a function.

Factory Functions

Factory functions are functions that return other functions.


def oneFactory(): () => Int = {
    () => {
        1
    }
}

Factory function oneFactory returns an anonymous function, that takes no arguments, and returns an integer(Always 1 in this case).

Functional Parameters

Functional parameters, or functional arguments, are parameters passed to a function or method that are anonymous functions.


def takesAFunction(functionalParameter: () => Int): Int = {
    functionalParameter()
}

We can now call takesAFunction with a call to oneFactory to give it a functional argument.


takesAFunction(oneFactory())


//Output: 1

When we call oneFactory, it returns a functional parameter, in the form of () => Int, to takesAFunction. takesAFunction then calls that function and returns its output.

Closures

The concept of a closure is that an anonymous function has access to everything that was in scope when it was created. That is, everything that was in scope is enclosed in the function.

Scope

Scope can be defined as all the variables and members a function or method has access to.


class AClass(aVariable: String){
    
    def aFunction(): () => Unit = {
        () => {
            //do something with aVariable
        }
    }

}

In the above, member aFunction has access to aVariable, because aVariable is in the scope of everything in AClass.

In return, the emitted anonymous function can do something with the value of aVariable at the time when aFunction was called.

Let's look at one of the most common examples of closures


def adderFactory(aValue: Int): (Int) => Int = {
    (anotherValue: Int) => {
        aValue + anotherValue
    }
}

val oneAdder: (Int) => Int = adderFactory(1)
val fiveAdder: (Int) => Int = adderFactory(5)

oneAdder(1)
//Output = 2
fiveAdder(1)
//Output: 6

As you can see, the oneAdder and fiveAdder functions have access to the value of the aValue variable as it was when adderFactory was called to create them. That is aValue was included in the closure when they were created.

Conclusion

In conclusion, closures happen when anonymous functions are created, enclosing the values of everything that was in scope at the time they are created.

Closures can have many uses, from timers to complicated computations. Using what you have seen here, you are well on your way to being a closure wizard.

Comments




Navagation