How to use functions as variables (values) in Scala

This is an excerpt from the Scala Cookbook (partially modified for the internet). This is Recipe 9.2, “How to use functions as variables (values) in Scala.”

Back to top

Problem

You want to pass a Scala function around like a variable, just like you pass String, Int, and other variables around in an object-oriented programming language.

Back to top

Solution

Use the syntax shown in Recipe 9.1 to define a function literal, and then assign that literal to a variable.

The following Scala code defines a function literal that takes an Int parameter and returns a value that is twice the amount of the Int that is passed in:

(i: Int) => { i * 2 }

As mentioned in Recipe 9.1, you can think of the => symbol as a transformer. In this case, the function transforms the Int value i to an Int value that is twice the value of i.

You can now assign that function literal to a variable:

val double = (i: Int) => { i * 2 }

The variable double is an instance, just like an instance of a String, Int, or other type, but in this case, it’s an instance of a function, known as a function value. You can now invoke double just like you’d call a method:

double(2)   // 4
double(3)   // 6

Beyond just invoking double like this, you can also pass it to any method (or function) that takes a function parameter with its signature. For instance, because the map method of a sequence is a generic method that takes an input parameter of type A and returns a type B, you can pass the double method into the map method of an Int sequence:

scala> val list = List.range(1, 5)
list: List[Int] = List(1, 2, 3, 4)

scala> list.map(double)
res0: List[Int] = List(2, 4, 6, 8)

Welcome to the world of functional programming.

Back to top

Discussion

You can declare a function literal in at least two different ways. I generally prefer the following approach, which implicitly infers that the following function’s return type is Boolean:

val f = (i: Int) => { i % 2 == 0 }

In this case, the Scala compiler is smart enough to look at the body of the function and determine that it returns a Boolean value. As a human, it’s also easy to look at the code on the right side of the expression and see that it returns a Boolean, so I usually leave the explicit Boolean return type off the function declaration.

However, if you prefer to explicitly declare the return type of a function literal, or want to do so because your function is more complex, the following examples show different forms you can use to explicitly declare that your function returns a Boolean:

val f: (Int) => Boolean = i => { i % 2 == 0 }
val f: Int => Boolean = i => { i % 2 == 0 }
val f: Int => Boolean = i => i % 2 == 0
val f: Int => Boolean = _ % 2 == 0

A second example helps demonstrate the difference of these approaches. These functions all take two Int parameters and return a single Int value, which is the sum of the two input values:

// implicit approach
val add = (x: Int, y: Int) => { x + y }
val add = (x: Int, y: Int) => x + y

// explicit approach
val add: (Int, Int) => Int = (x,y) => { x + y }
val add: (Int, Int) => Int = (x,y) => x + y

As shown, the curly braces around the body of the function in these simple examples are optional, but they are required when the function body grows to more than one expression:

val addThenDouble: (Int, Int) => Int = (x,y) => {
    val a = x + y
    2 * a
}
Back to top

Using a method like an anonymous function

Scala is very flexible, and just like you can define an anonymous function and assign it to a variable, you can also define a method and then pass it around like an instance variable. Again using a modulus example, you can define a method in any of these ways:

def modMethod(i: Int) = i % 2 == 0
def modMethod(i: Int) = { i % 2 == 0 }
def modMethod(i: Int): Boolean = i % 2 == 0
def modMethod(i: Int): Boolean = { i % 2 == 0 }

Any of these methods can be passed into collection methods that expect a function that has one Int parameter and returns a Boolean, such as the filter method of a List[Int]:

val list = List.range(1, 10)
list.filter(modMethod)

Here’s what that looks like in the REPL:

scala> def modMethod(i: Int) = i % 2 == 0
modMethod: (i: Int)Boolean

scala> val list = List.range(1, 10)
list: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9)

scala> list.filter(modMethod)
res0: List[Int] = List(2, 4, 6, 8)

As noted, this is similar to the process of defining a function literal and assigning it to a variable. The following function works just like the previous method:

val modFunction = (i: Int) => i % 2 == 0
list.filter(modFunction)

At a coding level, the obvious difference is that modMethod is a method defined in a class, whereas modFunction is a function that’s assigned to a variable. Under the covers, modFunction is an instance of the Function1 trait, which defines a function that takes one argument. (The scala package defines other similar traits, including Function0, Function2, and so on, up to Function22.)

Back to top

Assigning an existing function/method to a function variable

Continuing our exploration, you can assign an existing method or function to a function variable. For instance, you can create a new function named c from the scala.math.cos method using either of these approaches:

scala> val c = scala.math.cos _
c: Double => Double = <function1>

scala> val c = scala.math.cos(_)
c: Double => Double = <function1>

This is called a partially applied function. It’s partially applied because the cos method requires one argument, which you have not yet supplied (more on this in Recipe 9.6).

Now that you have c, you can use it just like you would have used cos:

scala> c(0)
res0: Double = 1.0

If you’re not familiar with this syntax, this is a place where the REPL can be invaluable. If you attempt to assign the cos function/method to a variable, the REPL tells you what’s wrong:

scala> val c = scala.math.cos
<console>:11: error: missing arguments for method cos in class MathCommon;
follow this method with `_' to treat it as a partially applied function
       val c = scala.math.cos
                          ^

The following example shows how to use this same technique on the scala.math.pow method, which takes two parameters:

scala> val p = scala.math.pow(_, _)
pow: (Double, Double) => Double = <function2>

scala> p(scala.math.E, 2)
res0: Double = 7.3890560989306495

If this seems like an interesting language feature, but you’re wondering where it would be useful, see Recipe 9.6, “Using Partially Applied Functions”, for more information.

Back to top

Summary notes

  • Think of the => symbol as a transformer. It transforms the input data on its left side to some new output data, using the algorithm on its right side.
  • Use def to define a method, val to create a function.
  • When assigning a function to a variable, a function literal is the code on the right side of the expression.
  • A function value is an object, and extends the FunctionN traits in the main scala package, such as Function0 for a function that takes no parameters.
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.