How to use closures in Scala (closure examples, syntax)

This is an excerpt from the Scala Cookbook (partially modified for the internet). This is Recipe 9.5, “How to use closures in Scala (closure examples, syntax).”

Back to top

Problem

You want to pass a Scala function around like a variable, and while doing so, you want that function to be able to refer to one or more fields that were in the same scope as the function when it was declared.

Back to top

Solution

You can demonstrate a closure in Scala with the following simple (but complete) example:

package otherscope {
    class Foo {
        // a method that takes a function and a string, and passes the string into
        // the function, and then executes the function
        def exec(f:(String) => Unit, name: String) {
            f(name)
        }
    }
}

object ClosureExample extends App {
    var hello = "Hello"
    def sayHello(name: String) { println(s"$hello, $name") }

    // execute sayHello from the exec method foo
    val foo = new otherscope.Foo
    foo.exec(sayHello, "Al")

    // change the local variable 'hello', then execute sayHello from
    // the exec method of foo, and see what happens
    hello = "Hola"
    foo.exec(sayHello, "Lorenzo")
}

To test this code, save it as a file named ClosureExample.scala, then compile and run it. When it’s run, the output will be:

Hello, Al
Hola, Lorenzo

If you’re coming to Scala from Java or another OOP language, you might be asking, “How could this possibly work?”

Not only did the sayHello method reference the variable hello from within the exec method of the Foo class on the first run (where hello was no longer in scope), but on the second run, it also picked up the change to the hello variable (from Hello to Hola). The simple answer is that Scala supports closure functionality, and this is how closures work.

As Dean Wampler and Alex Payne describe in their book Programming Scala (O’Reilly), there are two free variables in the sayHello method: name and hello. The name variable is a formal parameter to the function; this is something you’re used to.

However, hello is not a formal parameter; it’s a reference to a variable in the enclosing scope (similar to the way a method in a Java class can refer to a field in the same class). Therefore, the Scala compiler creates a closure that encompasses (or “closes over”) hello.

You could continue to pass the sayHello method around so it gets farther and farther away from the scope of the hello variable, but in an effort to keep this example simple, it’s only passed to one method in a class in a different package. You can verify that hello is not in scope in the Foo class by attempting to print its value in that class or in its exec method, such as with println(hello). You’ll find that the code won’t compile because hello is not in scope there.

Back to top

Discussion

In my research, I’ve found many descriptions of closures, each with slightly different terminology. Wikipedia defines a closure like this:

“In computer science, a closure (also lexical closure or function closure) is a function together with a referencing environment for the non-local variables of that function. A closure allows a function to access variables outside its immediate lexical scope.”

In his excellent article, Closures in Ruby, Paul Cantrell states, “a closure is a block of code which meets three criteria.” He defines the criteria as follows:

  1. The block of code can be passed around as a value, and
  2. It can be executed on demand by anyone who has that value, at which time
  3. It can refer to variables from the context in which it was created (i.e. it is closed with respect to variable access, in the mathematical sense of the word “closed”).

Personally, I like to think of a closure as being like quantum entanglement, which Einstein referred to as “a spooky action at a distance.” Just as quantum entanglement begins with two elements that are together and then separated — but somehow remain aware of each other — a closure begins with a function and a variable defined in the same scope, which are then separated from each other. When the function is executed at some other point in space (scope) and time, it is magically still aware of the variable it referenced in their earlier time together, and even picks up any changes to that variable.

As shown in the Solution, to create a closure in Scala, just define a function that refers to a variable that’s in the same scope as its declaration. That function can be used later, even when the variable is no longer in the function’s current scope, such as when the function is passed to another class, method, or function.

Any time you run into a situation where you’re passing around a function, and wish that function could refer to a variable like this, a closure can be a solution. The variable can be a collection, an Int you use as a counter or limit, or anything else that helps to solve a problem. The value you refer to can be a val, or as shown in the example, a var.

Back to top

A second example

If you’re new to closures, another example may help demonstrate them. First, start with a simple function named isOfVotingAge. This function tests to see if the age given to the function is greater than or equal to 18:

val isOfVotingAge = (age: Int) => age >= 18
isOfVotingAge(16)  // false
isOfVotingAge(20)  // true

Next, to make your function more flexible, instead of hardcoding the value 18 into the function, you can take advantage of this closure technique, and let the function refer to the variable votingAge that’s in scope when you define the function:

var votingAge = 18
val isOfVotingAge = (age: Int) => age >= votingAge

When called, isOfVotingAge works as before:

isOfVotingAge(16)  // false
isOfVotingAge(20)  // true

You can now pass isOfVotingAge around to other methods and functions:

def printResult(f: Int => Boolean, x: Int) {
    println(f(x))
}

printResult(isOfVotingAge, 20)  // true

Because you defined votingAge as a var, you can reassign it. How does this affect printResult? Let’s see:

// change votingAge in one scope
votingAge = 21

// the change to votingAge affects the result
printResult(isOfVotingAge, 20)  // now false

Cool. The field and function are still entangled.

Back to top

Using closures with other data types

In the two examples shown so far, you’ve worked with simple String and Int fields, but closures can work with any data type, including collections. For instance, in the following example, the function named addToBasket is defined in the same scope as an ArrayBuffer named fruits:

import scala.collection.mutable.ArrayBuffer

val fruits = ArrayBuffer("apple")

// the function addToBasket has a reference to fruits
val addToBasket = (s: String) => {
    fruits += s
    println(fruits.mkString(", "))
}

As with the previous example, the addToBasket function can now be passed around as desired, and will always have a reference to the fruits field. To demonstrate this, define a method that accepts a function with addToBasket’s signature:

def buyStuff(f: String => Unit, s: String) {
    f(s)
}

Then pass addToBasket and a String parameter to the method:

scala> buyStuff(addToBasket, "cherries")
cherries

scala> buyStuff(addToBasket, "grapes")
cherries, grapes

As desired, the elements are added to your ArrayBuffer.

Note that the buyStuff method would typically be in another class, but this example demonstrates the basic idea.

Back to top

A comparison to Java

If you’re coming to Scala from Java, or an OOP background in general, it may help to see a comparison between this closure technique and what you can currently do in Java. (In Java, there are some closure-like things you can do with inner classes, and closures are intended for addition to Java 8 in Project Lambda. But this example attempts to show a simple OOP example.)

The following example shows how a sayHello method and the helloPhrase string are encapsulated in the class Greeter. In the main method, the first two examples with Al and Lorenzo show how the sayHello method can be called directly.

At the end of the main method, the greeter instance is passed to an instance of the Bar class, and greeter’s sayHello method is executed from there:

public class SimulatedClosure {
    public static void main (String[] args) {
        Greeter greeter = new Greeter();
        greeter.setHelloPhrase("Hello");
        greeter.sayHello("Al");       // "Hello, Al"
        greeter.setHelloPhrase("Hola");
        greeter.sayHello("Lorenzo");  // "Hola, Lorenzo"
        greeter.setHelloPhrase("Yo");
        Bar bar = new Bar(greeter);   // pass the greeter instance to a new Bar
        bar.sayHello("Adrian");       // invoke greeter.sayHello via Bar
    }
}

class Greeter {
    private String helloPhrase;
    public void setHelloPhrase(String helloPhrase) {
        this.helloPhrase = helloPhrase;
    }
    public void sayHello(String name) {
        System.out.println(helloPhrase + ", " + name);
    }
}

class Bar {
    private Greeter greeter;
    public Bar (Greeter greeter) {
        this.greeter = greeter;
    }
    public void sayHello(String name) {
        greeter.sayHello(name);
    }
}

Running this code prints the following output:

Hello, Al
Hola, Lorenzo
Yo, Adrian

The end result is similar to the Scala closure approach, but the big differences in this example are that you’re passing around a Greeter instance (instead of a function), and sayHello and the helloPhrase are encapsulated in the Greeter class. In the Scala closure solution, you passed around a function that was coupled with a field from another scope.

Back to top

See Also

Back to top

The Scala Cookbook

This tutorial is sponsored by the Scala Cookbook, which I wrote for O’Reilly:

You can find the Scala Cookbook at these locations:

Back to top

Add new comment

The content of this field is kept private and will not be shown publicly.

Anonymous format

  • Allowed HTML tags: <em> <strong> <cite> <code> <ul type> <ol start type> <li> <pre>
  • Lines and paragraphs break automatically.
By submitting this form, you accept the Mollom privacy policy.