Scala’s versatile unapply method

Robin Hillyard
2 min readJan 7, 2023

--

Preparing some code for my latest batch of Scala students, I wrote a Scala FizzBuzz. The straightforward, obvious, way to write the fizzBuzz method is:

    def fizzBuzz(x: Int): String =
if (x % 3 == 0 && x % 5 == 0) "FizzBuzz"
else if (x % 3 == 0) "Fizz"
else if (x % 5 == 0) "Buzz"
else x.toString

This is not totally satisfying, however, as we test divisibility by 3 and 5 twice each. And, further, it would be rather more elegant if we could use pattern-matching instead of if clauses.

But, how can we rewrite this with pattern-matching? That’s where the unapply method comes in. Normally, the unapply method is automagically generated for case classes in the companion object and we think nothing more of it. But, we can write our own—and even make it an instance method, i.e. declared in the class.

But first, we need to create a case class to represent factorization, Factor:

case class Factor(f: Int) {
def isMultiple(x: Int): Boolean = x % f == 0

def unapply(x: Int): Option[Int] = if (isMultiple(x)) Some(x / f) else None
}

There is a method isMultiple(x) which returns true if f divides x exactly. Then there is the unapply(x) method which yields a Some[Int] if x is a multiple of x; None otherwise. The wrapped value is the quotient (x/f). In our application, we actually ignore the quotient because all we care about for fizzBuzz is factors.

Similar to pattern-matching on regular expressions, we need to create Factor values first:

    private lazy val dividesBy3: Factor = Factor(3)
private lazy val dividesBy5 = Factor(5)
private lazy val dividesBy3And5 = Factor(3 * 5)

And now we’re ready to create our pattern-matching-based fizzBuzz:

    def fizzBuzz(x: Int): String = x match {
case dividesBy3And5(_) => "FizzBuzz"
case dividesBy3(_) => "Fizz"
case dividesBy5(_) => "Buzz"
case _ => x.toString
}

We run the program with the following code:

    private val strings = for (x <- 1 to 100) yield fizzBuzz(x)
println(strings mkString("", "\n", ""))

Clearly, we’ve ended up writing a lot more code than the original, simple FizzBuzz. But I hope that, for some readers at least, I’ve added to the pattern-matching tools that you have available to you. If you appreciate the elegance of the solution, so much the better.

--

--

Robin Hillyard
Robin Hillyard

Written by Robin Hillyard

I’ve been addicted to programming for over 50 years now. I currently teach two classes to graduates at Northeastern University, Boston, USA.

No responses yet