“Call me, call me by my name, or call me by number.”
Introduction
In the previous functional programming 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 a common technique in functional programming.
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.
Goals
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
Background: By-value parameters
If you define a Person
class like this:
case class Person(var name: String)
and then pass a Person
instance 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. In this example, 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:
val fred = Person("Fred") changeName(fred) println(fred.name) // "Al"
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
)
Background: By-name parameters
“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.
Example: Creating a timer
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.
Designing a Scala timer
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.
Trying to define a function signature
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.
By-name syntax
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:
// returns a result and the number of ms the block takes to run
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 }
Note that the
time
value is in milliseconds, so a result of 2978.106758 is 2.978 seconds.
“When is my code block run?”
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.
The updated timer code
As a brief note, I recently updated the timer code to look like this with Scala 3:
/** * Note that `timer { Thread.sleep(2_000) }` is * returned as `2007.09575` or something close * to that. */ def timer[A](blockOfCode: => A): (A, Double) = val startTime = System.nanoTime val result = blockOfCode val stopTime = System.nanoTime val delta = stopTime - startTime (result, delta/1_000_000d)
Another example: A Swing utility
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.
this post is sponsored by my books: | |||
#1 New Release |
FP Best Seller |
Learn Scala 3 |
Learn FP Fast |
Why have by-name parameters?
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:
- Imagine that Scala does not have an
assert
function, and you want one. - 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 the them differently.
Summary
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
See also
- My free video on “How and why to use multiple parameter groups in Scala”
- On StackOverflow, Daniel Sobral has a nice answer to a question about the difference between
(f: A => B)
and(f: () => A)
- Scala Puzzlers comments about function input parameters
- Evaluation strategy on Wikipedia