Scala allows you to write your code in such a way as to give the impression that you’re working with native language constructs, when really you’re just working with regular methods.
This chapter will cover:
These things don’t sound that impressive, but combined they allow for a surprising amount of flexibility. We’ll see how these techniques can help you write more flexible and readable code.
All the code samples in this chapter are in Scala.
There’s a simple rule in Scala:
Any method call which accepts exactly one argument can use curly braces to surround the argument instead of parentheses.
So, instead of this:
numerals
.
foreach
(
println
(
_
))
You can write this:
numerals
.
foreach
{
println
(
_
)}
All we’ve done is swap the brackets for curly braces. Not very impressive, but things start to look a bit more interesting when we introduce some new lines.
numerals
.
foreach
{
println
(
_
)
}
Now it begins to look like a built-in control structure. Developers are used to interpreting curly braces as demarcation of language syntax. So this looks more like the built-in for
loop, even though it’s just a method call.
The main reason for doing this is to allow clients to pass in functions as arguments in a natural and concise way. When you write functions that can take functions as arguments, you’re creating higher-order functions. These allow for greater flexibility and re-use.
For example, let’s say we want to do some work and update a UI element, like a progress bar or a customer basket. The best way to do this is in a new thread so that we don’t slow down the main UI thread and cause pauses for the user.
If every call to update a UI element must be done on its own thread, we might end up with a naive implementation like this:
object
Ui
{
def
updateUiElements
()
{
new
Thread
()
{
override
def
run
()
:
Unit
=
updateCustomerBasket
(
basket
)
}.
start
()
new
Thread
()
{
override
def
run
()
:
Unit
=
updateOffersFor
(
customer
)
}.
start
()
}
}
The Ui
object executes the sequence of updates one after another, each on a new thread. The Ui
object is managing the threading policy and the update behaviour. It would be better if something else was responsible for coordinating threading and the Ui
object was left to the update behaviour. That way, we could avoid duplication and if the threading policy changes, we wouldn’t have to find all the usages scattered about the place.
The solution is to define a function that can run some other function on a thread. We could create a function called runInThread
with the boilerplate threading code.
def
runInThread
()
{
new
Thread
()
{
override
def
run
()
:
Unit
=
???
}.
start
()
}
It will create and start a new thread but it doesn’t do anything interesting. How do we pass in a function? In Java, you’d probably pass in a anonymous instance of a Runnable
or Callable
or a lambda.
You do the same in Scala but rather than pass in a functional interface as the argument, you pass in a shorthand signature denoting a function argument. You define a variable as usual (function
in our example below) but the type that follows the colon represents a function. Our example has no arguments and returns a value of Unit
. It’s equivalent to Java 8’s signature for a lambda: () -> Void
.
def
runInThread
(
function
:
()
=>
Unit
)
{
new
Thread
()
{
override
def
run
()
:
Unit
=
???
}.
start
()
}
Then we just execute the function in the body of the thread. Remember the brackets denote the shorthand for executing the apply
method.
def
runInThread
(
function
:
()
=>
Unit
)
{
new
Thread
()
{
override
def
run
()
:
Unit
=
function
()
// aka function.apply()
}.
start
()
}
Given the new runInThread
method, we can rewrite the UI code like this:
def
updateUiElements
()
{
runInThread
(()
=>
updateCustomerBasket
(
basket
))
runInThread
(()
=>
updateOffersFor
(
customer
))
}
We’ve eliminated the duplication by passing in functions to runInThread
.
This doesn’t really live up to the promise of clients being able to pass functions as arguments “in a natural and concise way”. It looks a lot like Java’s lambda syntax, but we can make it look more natural and more like language syntax if we use the curly braces.
If we just replace the parentheses with curly braces, it doesn’t really improve things.
// yuk!
def
updateUiElements
()
{
runInThread
{
()
=>
updateCustomerBasket
(
basket
)
}
runInThread
{
()
=>
updateOffersFor
(
customer
)
}
}
But we can employ another trick to get rid of the empty parentheses and arrows. We can used what’s called a call-by-name parameter.
In Java, you can’t do anything about an empty lambda argument list (e.g., () -> Void
) but in Scala, you can drop the brackets from a function signature to indicate that the argument is call-by-name. To invoke it, you no longer need to call the apply
method. Instead, you simply reference it.
def
runInThread
(
function
:
=>
Unit
)
{
// call-by-name
new
Thread
()
{
override
def
run
()
:
Unit
=
function
// not function()
}.
start
()
}
The by-name parameter expression isn’t evaluated until it’s actually used; not when it’s defined. It behaves just like the longhand function did even though it looks like we’re calling the function at the point where we pass it into our runInThread
method.
def
updateUiElements
()
{
runInThread
{
updateCustomerBasket
(
basket
)
}
runInThread
{
updateOffersFor
(
customer
)
}
}
This starts to make things look a lot more natural, especially if we want to do more within a running thread. For example, let’s say we want to apply a discount before updating a customer’s basket. The braces and indents make it very clear that this happens in the same thread as the update.
def
updateUiElements
()
{
runInThread
{
applyDiscountToBasket
(
basket
)
updateCustomerBasket
(
basket
)
}
runInThread
{
updateOffersFor
(
customer
)
}
}
You can think of it as shorthand for creating a parameter-less lambda.
Using the apply
method and curly braces allows us to create APIs that are expressive and natural to use. It allows us to create control abstractions that conform to what we already expect from the language in terms of syntax.
But remember what we said earlier about the curly braces rule.
Any method call which accepts exactly one argument can use curly braces to surround the argument instead of parentheses.
We can only use curly braces with single-argument methods. What if we want to add an argument to our runInThread
method and still use the elegant syntax? The good news is that it’s entirely possible; we employ a technique called currying.
Let’s extend our runInThread
method to add a new argument to assign a thread group.
def
runInThread
(
group
:
String
,
function
:
=>
Unit
)
{
new
Thread
(
new
ThreadGroup
(
group
),
new
Runnable
()
{
def
run
()
:
Unit
=
function
}).
start
()
}
As only single-argument lists can use braces, we have to regress the Ui
object back to using parentheses.
// yuk!
def
updateUiElements
()
{
runInThread
(
"basket"
,
{
applyDiscountToBasket
(
basket
)
updateCustomerBasket
(
basket
)
})
runInThread
(
"customer"
,
updateOffersFor
(
customer
)
)
}
If we could convert our function with two arguments into a function that takes one argument we’d be able to use the curly braces again. Fortunately for us, that’s exactly what currying is about. Currying is the process of turning a function of two or more arguments into a series of functions, each taking a single argument.
For a function of two arguments, currying would produce a function that takes one argument and returns another function. This returned function would also have a single argument (for what would have been the second argument of the original function). Confused? Let’s work through an example.
Let’s say we have a function that takes two arguments, and , and returns .
To convert this into two functions, each with a single argument, first we create a function to take and give back a new function ().
This new function should itself take a single argument, .
That entire function should return the result,
We’re left with two functions ( and ), each taking a single argument.
With the pseudo-mathematical notation on the same page, it’s worth restating my original definition and comparing the original to the curried form of the function.
For a function of two arguments, currying would produce a function that takes one argument and returns another function. This returned function would also have a single argument (for what would have been the second argument of the original function).
To evaluate the functions of the curried form, we’d evaluate the first function (for example, passing in a value ).
This would return a function which captures the value, and because what’s returned is a function, we can just evaluate it, providing a value for the last argument ().
At this point, both values are in scope and any computation can be applied giving the final result.
I’ve been using a bit of a gorilla notation to get my point across here. Using a more mathematically correct notation, we could show the function as being curried by creating a new function taking and mapping to .
If you’re familiar with the lambda calculus, you’ll already know that is shorthand for its curried form .
A regular uncurried function to add two numbers might look like this:
def
add
(
x
:
Int
,
y
:
Int
)
:
Int
=
x
+
y
Scala supports curried functions out of the box, so we don’t need to do any manual conversion; all we do to turn this into its curried version is to separate out the arguments using parentheses.
def
add
(
x
:
Int
)(
y
:
Int
)
:
Int
=
x
+
y
Scala has created two single-argument parameter lists for us. To evaluate the function, we’d do the following:
scala
>
add
(
1
)(
2
)
res1
:
Int
=
3
To see it in stages, we could just evaluate the first half like this:
scala
>
val
f
=
add
(
1
)
_
f
:
Int
=>
Int
=
<
function1
>
The underscore gives the REPL a hint about what we’re trying to do. The result f
is a function from Int
to Int
. The value 1
has been captured and is available to that function. So we can now just execute the returned function supplying our second value.
scala
>
f
(
2
)
res2
:
Int
=
3
So what does this mean for our runInThread
method? Well, if we create a curried version of the function, we can get back to using our lovely curly braces.
We start by splitting the argument into two to create the curried form of the original.
def
runInThread
(
group
:
String
)(
function
:
=>
Unit
)
{
new
Thread
(
new
ThreadGroup
(
group
),
new
Runnable
()
{
def
run
()
:
Unit
=
function
}).
start
()
}
Notice there are no other changes to make to the function. Inside runInThread
everything is just as it was. However, we can now change the Ui
object back to using curly braces for the second argument.
def
updateUiElements
()
{
runInThread
(
"basket"
)
{
applyDiscountToBasket
(
basket
)
updateCustomerBasket
(
basket
)
}
runInThread
(
"customer"
,
updateOffersFor
(
customer
)
)
}
With a few built-in features, Scala allows us to write methods that look like language constructs. We can use higher-order functions to create control abstractions: functions that abstract over complex behaviour and reduce duplication yet still offer flexibility to the code that calls them.
We can use curly braces anywhere a single-argument method is used. We can use this to provide visual cues and patterns that are immediately recognisable. Using built-in currying support, we’re not limited to using this only for single-argument functions; we can create even richer APIs by converting multiple-argument functions into multiple single-argument functions.