This is an excerpt from the 1st Edition of the Scala Cookbook (partially modified for the internet). This is Recipe 3.18, “How to create your own control structures in Scala.”
Problem
You want to define your own control structures to improve the Scala language, simplify your own code, or create a DSL for others to use.
Solution
The creators of the Scala language made a conscious decision not to implement some keywords in Scala, and instead implemented functionality through Scala libraries. This was demonstrated in Recipe 3.5, “Implementing break and continue”, which showed that although the Scala language doesn’t have break
and continue
keywords, you can achieve the same functionality through library methods.
As a simple example of creating what appears to be a control structure, imagine for a moment that for some reason you don’t like the while
loop and want to create your own whilst
loop, which you can use like this:
package foo import com.alvinalexander.controls.Whilst._ object WhilstDemo extends App { var i = 0 whilst (i < 5) { println(i) i += 1 } }
To create your own whilst
control structure, define a function named whilst
that takes two parameter lists. The first parameter list handles the test condition — in this case, i < 5
— and the second parameter list is the block of code the user wants to run.
You could implement this as a method that’s just a wrapper around the while
operator:
// 1st attempt def whilst(testCondition: => Boolean)(codeBlock: => Unit) { while (testCondition) { codeBlock } }
But a more interesting approach is to implement the whilst
method without calling while
. This is shown in a complete object here:
package com.alvinalexander.controls import scala.annotation.tailrec object Whilst { // 2nd attempt @tailrec def whilst(testCondition: => Boolean)(codeBlock: => Unit) { if (testCondition) { codeBlock whilst(testCondition)(codeBlock) } } }
In this code, the testCondition
is evaluated once, and if the condition is true
, the codeBlock
is executed, and then whilst
is called recursively. This approach lets you keep checking the condition without needing a while
or for
loop.
Discussion
In the second whilst
example, I used a recursive call to keep the loop running, but in a simpler example, you don’t need recursion. For example, assume you want a control structure that takes two test conditions, and if both evaluate to true
, you’ll run a block of code that’s supplied. An expression using that control structure might look like this:
doubleif(age > 18)(numAccidents == 0) { println("Discount!") }
In this case, define a function that takes three parameter lists:
// two 'if' condition tests def doubleif(test1: => Boolean)(test2: => Boolean)(codeBlock: => Unit) { if (test1 && test2) { codeBlock } }
Because doubleif
only needs to perform one test and doesn’t need to loop indefinitely, there’s no need for a recursive call in its method body. It simply checks the two test conditions, and if they evaluate to true, the codeBlock
is executed.
See Also
- One of my favorite uses of this technique is shown in the book, Beginning Scala (Apress), by David Pollak. I describe how it works on my website.
- The Scala
Breaks
class is demonstrated in Recipe 3.5. Its source code is simple, and provides another example of how to implement a control structure.
this post is sponsored by my books: | |||
#1 New Release |
FP Best Seller |
Learn Scala 3 |
Learn FP Fast |