How To Use By-Name Parameters

In previous lessons I showed how to pass a function into another function. I showed how to do that (the syntax), and I also showed why to do that (to easily pass in new algorithms).

While that’s a great feature, sometimes you just want to write a function that takes a more general “block of code.” I typically do this when I’m writing a custom control structure, and as it turns out it’s also common technique in FP.

In Scala we say that a function that defines an input parameter like this is a “by-name” parameter, which is also referred to as a “call by-name” parameter.

Given that introduction, my goals for this lesson are to show:

  • The differences between by-value and by-name parameters

  • The by-name syntax

  • How to use by-name parameters

  • Examples of when they are appropriate

  • A comparison of by-name parameters and higher-order functions

If you define a Person class like this:

case class Person(var name: String)

and then pass it into a Scala function, it’s said to be a “call by-value” argument. You can read much more about this on Wikipedia’s “evaluation strategy” page, but in short, I think of this as the function receiving a pointer to the object that’s passed in.

This has a few repercussions. First, it means that there’s no copy of the object. Under the covers, the function essentially receives a pointer that says, “You can find this Person instance at so-and-so memory address in the computer’s RAM.”

Second, if the object has mutable fields, the function can mutate those fields. When a function receives a Person instance and the name field is a var, the function can change the name:

def changeName(p: Person) = {
    p.name = "Al"
}

This change affects the Person instance that was passed in.

In regards to the name “by-value,” the book, Programming Scala, makes this statement:

“Typically, parameters to functions are by-value parameters; that is, the value of the parameter is determined before it is passed to the function.”

In summary, in Scala the term “call by-value” means that the value is either:

  • A primitive value (like an Int) that can’t be changed

  • A pointer to an object (like Person)

“By-name” parameters are quite different than by-value parameters. Rob Norris, (aka, “tpolecat”) makes the observation that you can think about the two types of parameters like this:

  • A by-value parameter is like receiving a val field; its body is evaluated once, when the parameter is bound to the function.

  • A by-name parameter is like receiving a def method; its body is evaluated whenever it is used inside the function.

Those statements aren’t 100% accurate, but they are decent analogies to start with.

A little more accurately, the book Scala Puzzlers says that by-name parameters are “evaluated only when they are referenced inside the function.” The Scala Language Specification adds this:

This (by-name) indicates that the argument is not evaluated at the point of function application, but instead is evaluated at each use within the function.

According to Wikipedia these terms date back to a language named ALGOL 60 (yes, the year 1960). But for me, the term “by-name” isn’t very helpful. When you look at those quotes from the Puzzlers book and the Language Specification, you see that they both say, “a by-name parameter is only evaluated when it’s accessed inside a function.” Therefore, I find that the following names are more accurate and meaningful than “by-name”:

  • Call on access

  • Evaluate on access

  • Evaluate on use

  • Evaluate when accessed

  • Evaluate when referenced

However, because I can’t change the universe, I’ll continue to use the terms “by-name” and “call by-name” in this lesson, but I wanted to share those alternate names, which I think are more meaningful.

Okay, that’s enough background about the names. Let’s look at some code that shows how to create a by-name parameter, and what it gives you.

On Unix systems you can run a time command (timex on some systems) to see how long commands take to execute:

$ time find . -name "*.scala"

That command returns the results of the find command it was given, along with the time it took to run. The time portion of the output looks like this:

real  0m4.351s
user  0m0.491s
sys   0m1.341s

This is cool, and it can be a helpful way to troubleshoot performance problems. In fact, seeing how cool it is, you decide that you’d like to create a similar “timer” method in Scala.

Thinking in advance about how your new timer function should work, you decide that a nice API will let you write code like this:

val (result, time) = timer(someLongRunningAlgorithm)

and this:

val (result, time) = timer {
    ...
    ...
}

A timer like this gives you both the result of the algorithm and the time it took to run.

Assuming you already have a working timer, you can see how this works by running an example in the REPL:

scala> val (result, time) = timer{ Thread.sleep(500); 1 }
result: Int = 1
time: Double = 500.32

As expected, the code block returns the value 1, with an execution time of about 500 ms.

Having just seen how to define signatures for function input parameters in the previous lessons, you realize that you know how to write a timer … or at least you think you can.

The problem you run into right away is, “Just what is that algorithm that’s being passed in?” It could look like this:

def timer(f:(Int) => Int) ...

or this:

def timer(f:(Double) => Double) ...

or anything else:

def timer(f:() => Unit) ...
def timer(f:(Person) => String) ...
def timer(f:(Pizza, Order) => Double) ...
def timer(f:(Pizza, Order, Customer, Discounts) => Currency) ...

“Hmm,” you begin thinking, “this is quite a problem …”

Fortunately the Scala creators gave us a nice solution for problems like these.

The solution for situations like this is to use Scala’s by-name syntax. It’s similar to defining function input parameters, but it also makes problems like this simple.

The general syntax for defining a by-name parameter looks like this:

def timer(blockOfCode: => theReturnType) ...

If you look back at the function input parameter examples, you’ll see that the by-name syntax is similar to this example:

def timer(f:() => Unit) ...

The main difference is that you leave off the () after the input parameter.

Given that brief introduction to the by-name syntax, to create a timer that can accept a block of code that returns any type, you make the return type generic. Therefore, I can sketch the timer signature like this:

def timer[A](blockOfCode: => A) = ???

With that signature in hand, I can then complete the timer function like this:

def timer[A](blockOfCode: => A) = {
    val startTime = System.nanoTime
    val result = blockOfCode
    val stopTime = System.nanoTime
    val delta = stopTime - startTime
    (result, delta/1000000d)
}

The timer method uses the by-name syntax to accept a block of code as an input parameter. Inside the timer function there are three lines of code that deal with determining how long the blockOfCode takes to run, with this line sandwiched in between those time-related expressions:

    val result = blockOfCode

That line (a) executes blockOfCode and (b) assigns its return value to result. Because blockOfCode is defined to return a generic type (A), it may return Unit, an Int, a Double, a Seq[Person], a Map[Person, Seq[Person]], whatever.

Now you can use the timer function for all sorts of things. It can be used for something that isn’t terribly useful, like this:

scala> val (result, time) = timer(println("Hello"))
Hello
result: Unit = ()
time: Double = 0.160

It can be used for an algorithm that reads a file and returns an iterator:

scala> def readFile(filename: String) = io.Source.fromFile(filename).getLines
readFile: (filename: String)Iterator[String]

scala> val (result, time) = timer(readFile("/etc/passwd"))
result: Iterator[String] = non-empty iterator
time: Double = 32.119

Or it can be used for just about anything else:

val (result, time) = timer{ someLongRunningAlgorithmThatReturnsSomething }

A great question right now is, “When are my by-name parameters executed?”

In the case of the timer function, it executes the blockOfCode when the second line of the function is reached. But if that doesn’t satisfy your curious mind, you can create another example like this:

def test[A](codeBlock: => A) = {
    println("before 1st codeBlock")
    val a = codeBlock
    println(a)
    Thread.sleep(10)

    println("before 2nd codeBlock")
    val b = codeBlock
    println(b)
    Thread.sleep(10)

    println("before 3rd codeBlock")
    val c = codeBlock
    println(c)
}

If you paste that code into the Scala REPL, you can then test it like this:

scala> test( System.currentTimeMillis )

That line of code will produce output like this:

before 1st codeBlock
1480206447942
before 2nd codeBlock
1480206447954
before 3rd codeBlock
1480206447966

As that output shows, the block of code that is passed in is executed each time it’s referenced inside the function.

As another example of how I use this technique, when I was writing a lot of Swing (GUI) code with Scala, I wrote this invokeLater function to accept blocks of code that should be run on the JVM’s Event Dispatch Thread (EDT):

def invokeLater(codeBlock: => Unit) {
    SwingUtilities.invokeLater(new Runnable() {
        def run() {
            codeBlock
        }
    });
}

invokeLater defines codeBlock as a by-name input parameter, and codeBlock is expected to return Unit (nothing). I defined it like that because every block of code it accepts is intended to update the Swing GUI, which means that each code block is used to achieve that side effect.

As an example, here are two example calls to invokeLater from my Sarah application:

invokeLater(mainFrame.setSarahIsSleeping())
invokeLater(mainFrame.setSarahIsListening())

In these examples, mainFrame.setSarahIsSleeping() and mainFrame.setSarahIsListening() are both function calls, and those functions do whatever they need to do to update the Sarah’s Swing GUI.

Knowing how those functions work, if for some reason I didn’t have them written as functions, I could have passed this block of code into invokeLater to achieve the same effect as the first example:

invokeLater {
    val controller = mainController.getMainFrameController()
    controller.setBackground(SARAH_IS_SLEEPING_COLOR)
}

Either approach — passing in a function, or passing in a block of code — is valid.

Programming in Scala, written by Martin Odersky and Bill Venners, provides a great example of why by-name parameters were added to Scala. Their example goes like this:

  1. Imagine that Scala does not have an assert function, and you want one.

  2. You attempt to write one using function input parameters, like this:

def myAssert(predicate: () => Boolean) = 
    if (assertionsEnabled && !predicate())
        throw new AssertionError

That code uses the “function input parameter” techniques I showed in previous lessons, and assuming that the variable assertionsEnabled is in scope, it will compile just fine.

The problem is that when you go to use it, you have to write code like this:

myAssert(() => 5 > 3)

Because myAssert states that predicate is a function that takes no input parameters and returns a Boolean, that’s how you have to write this line of code. It works, but it’s not pleasing to the eye.

The solution is to change predicate to be a by-name parameter:

def byNameAssert(predicate: => Boolean) =
    if (assertionsEnabled && !predicate)
        throw new AssertionError

With that simple change, you can now write assertions like this:

byNameAssert(5 > 3)

That’s much more pleasing to look at than this:

myAssert(() => 5 > 3)

Programming in Scala states that this is the primary use case for by-name parameters:

The result is that using byNameAssert looks exactly like using a built-in control structure.

If you want to experiment with this code, here’s the source code for a small but complete test class I created from their example:

object ByNameTests extends App {

    var assertionsEnabled = true

    def myAssert(p: () => Boolean) =
        if (assertionsEnabled && !p())
            throw new AssertionError

    myAssert(() => 5 > 3)

    def byNameAssert(p: => Boolean) =
        if (assertionsEnabled && !p)
            throw new AssertionError

    byNameAssert(5 > 3)

}

As you can see from that code, there’s only a small syntactical difference between defining a function input parameter that takes no input parameters and a by-name parameter:

p: () => Boolean    // a function input parameter
p: => Boolean       // a by-name parameter

As you can also tell from these two lines:

myAssert(() => 5 > 3)
byNameAssert(5 > 3)

you need to call them differently.

This lesson showed:

  • The differences between by-value and by-name parameters

  • Examples of the by-name syntax

  • How to use by-name parameters in your functions

  • Examples of when by-name parameters are appropriate

  • Some comparisons of by-name parameters and higher-order functions

results matching ""

    No results matching ""