DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workkloads.

Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Thermometer Continuation in Scala
  • Deploying a Scala Play Application to Heroku: A Step-by-Step Guide
  • Upgrading Spark Pipelines Code: A Comprehensive Guide
  • Java vs. Scala: Comparative Analysis for Backend Development in Fintech

Trending

  • How To Replicate Oracle Data to BigQuery With Google Cloud Datastream
  • Measuring the Impact of AI on Software Engineering Productivity
  • Beyond Microservices: The Emerging Post-Monolith Architecture for 2025
  • The Cypress Edge: Next-Level Testing Strategies for React Developers
  1. DZone
  2. Coding
  3. Languages
  4. 8 Scala Pattern Matching Tricks

8 Scala Pattern Matching Tricks

By 
Daniel Ciocirlan user avatar
Daniel Ciocirlan
·
Apr. 02, 20 · Tutorial
Likes (7)
Comment
Save
Tweet
Share
25.9K Views

Join the DZone community and get the full member experience.

Join For Free

You can't be a Scala programmer and say you've never used pattern matching — it is one of the most powerful Scala features. It allows one to test lots of values and conditions without nested and chained if-else expressions.

This article is for the Scala programmer who is either, a) only getting started with Scala, or b) has only used pattern matching in its basic form — as a switch-on-steroids or to deconstruct case classes.

This article will give you some tools to use pattern matching to the max. You can also watch it in video form on YouTube or attached below:


1. List Extractors

Lists can be deconstructed with pattern matching in a number of powerful ways. Let me build a list:

Scala
xxxxxxxxxx
1
 
1
val countingList = List(1,2,3,42)


You can extract any element out of this list with a pattern that looks like the case class constructor:

Scala
xxxxxxxxxx
1
 
1
val mustHaveThree = countingList match {
2
   case List(_, _, 3, somethingElse) => s"A-HA! I've got a list with 3 as third element, I found $somethingElse after"
3
}


This pattern matches a list with exactly four elements, in which we don't care about the first two. The third one must be exactly 3, and the fourth can be anything, but we name it, somethingElse, so we can reuse it in the s-interpolated string.

2. Haskell-Like Prepending

If I consider the same list as before, I can extract the head and tail of the list as follows:

Scala
xxxxxxxxxx
1
 
1
val startsWithOne = countingList match {
2
    case 1 :: someOtherElements => "This lists starts with one, the rest is $someOtherElements"
3
}


Don't ask how this is possible yet. That will be the subject of an upcoming advanced article. The prepend pattern is often very useful in code that processes a list, but when you don't know in advance whether the list is empty or not, you write it like this:

Scala
xxxxxxxxxx
1
 
1
def processList(numbers: List[Int]): String = numbers match {
2
    case Nil => ""
3
    case h :: t => h + " " + processList(t)
4
}


This style of handling a list may be very familiar to those of you who know a bit of Haskell.

3. List Vararg Pattern

The first pattern we showed above can only constrain a list to a definitive number of elements. What if you don't know (or care about) the number of elements in advance?

Scala
xxxxxxxxxx
1
 
1
val dontCareAboutTheRest = countingList match {
2
    case List(_, 2, _*) => "I only care that this list has 2 as second element"
3
}


The _* is the important bit, which means "any number of additional arguments". This pattern is much more flexible because an (almost) infinite number of lists can match this pattern, instead of the 4-element list pattern we had before. The only catch with _* is that it must be the last bit in the pattern. In other words, the case, List(_, 2, _*, 55), will not compile, for example.

4. Other List Infix Patterns

It's very useful when we can test the head of the list, or even the elements inside the list. But, what if we want to test the last element of the list?

Scala
xxxxxxxxxx
1
 
1
val mustEndWithMeaningOfLife = countingList match {
2
    case List(1,2,_) :+ 42 => "found the meaning of life!"
3
}


The :+ is the append operator, which works much like :: from the point of view of pattern matching. You can also use the +: prepend operator (for symmetry), but we prefer ::. A nice benefit of the append operator is that we can combine it with the vararg pattern for a really powerful structure:

Scala
xxxxxxxxxx
1
 
1
val mustEndWithMeaningOfLife2 = countingList match {
2
    case List(1, _*) :+ 42 => "I really don't care what comes before the meaning of life"
3
}


(Look for the _*), which overcomes some of the limitations of the vararg pattern above.

5. Type Specifiers

Sometimes, we really don't care about the values being matched, but only their type.

Scala
xxxxxxxxxx
1
 
1
def gimmeAValue(): Any = { ... }
2
3
val gimmeTheType = gimmeAValue() match {
4
    case _: String => "I have a string"
5
    case _: Int => "I have a number"
6
    case _ => "I have something else"
7
}


The :String bit is the important part. It allows the cases to match only those patterns that conform to that type. One very useful scenario where this is particularly useful is when we catch exceptions:

Scala
xxxxxxxxxx
1
 
1
try { 
2
    ...
3
} catch {
4
    case _: IOException => "IO failed!"
5
    case _: Exception => "We could have prevented that!"
6
    case _: RuntimeException => "Something else crashed!"
7
}


(Spoiler: catching exceptions is also based on pattern matching!)

The drawback with type guards is that they are based on reflection. Beware of performance hits!

6. Name Binding

I've seen the following pattern more times than I can count:

Scala
xxxxxxxxxx
1
 
1
def requestMoreInfo(p: Person): String = { ... }
2
3
val bob = Person("Bob", 34, List("Inception", "The Departed"))
4
5
val bobsInfo = bob match {
6
    case Person(name, age, movies) => s"$name's info: ${requestMoreInfo(Person(name, age, movies))}"
7
}


We deconstruct a case class only to re-instantiate it with the same data for later. If we didn't care about any field in the case class, that would be fine because we would use a type specifier (see above). Even that is not 100% fine because we rely on reflection. But, what if we care about some fields (not all) and the entire instance. Can we reuse those?

Scala
xxxxxxxxxx
1
 
1
val bobsInfo = bob match {
2
    case p @ Person(name, _, _) => s"$name's info: ${requestMoreInfo(p)}"
3
}


Answer: name the pattern you're matching (see the p @) so you can reuse it later. You can even name sub-patterns:

Scala
xxxxxxxxxx
1
 
1
val bobsInception = bob match {
2
    case Person(name, _, movies @ List("Inception", _*)) => s"$name REALLY likes Inception, some other movies too: $movies"
3
}


7. Conditional Guards

If you're like me, you probably tried at least once to pattern match something that satisfies a condition, and because you only knew the "anything" and "constant" patterns, you gave up pattern matching and used chained if-elses instead. 

Scala
 
xxxxxxxxxx
1
 
1
val ordinal = gimmeANumber() match {
2
    case 1 => "first"
3
    case 2 => "second"
4
    case 3 => "third"
5
    case n if n % 10 == 1 => n + "st"
6
    case n if n % 10 == 2 => n + "nd"
7
    case n if n % 10 == 3 => n + "rd"
8
    case n => n + "th"
9
}


As you can see above, the if guards are there directly in the pattern. Also notice that the condition does not have parentheses.

8. Alternative Patterns

For situations where you return the same expression for multiple patterns, you don't need to copy and paste the same code.

Scala
 
xxxxxxxxxx
1
 
1
val myOptimalList = numbers match {
2
    case List(1, _, _) => "I like this list"
3
    case List(43, _*) => "I like this list"
4
    case _ => "I don't like it"
5
}


You can combine the patterns where you return the same expression into a single pattern:

Scala
 
xxxxxxxxxx
1
 
1
val myOptimalList = numbers match {
2
    case List(1, _, _) | List (43, _*) => "I like this list"
3
    case _ => "I don't like it"
4
}


The only drawback of this pattern is that you can't bind any names because the compiler can't ensure those values are available on the right-hand side.

This pattern is useful in practice for a lot of scenarios, for example when you want to handle many kinds of exceptions:

Scala
xxxxxxxxxx
1
 
1
try {
2
    ...
3
} catch {
4
    case _: RuntimeException | _: IOException => ""
5
}


Until Next Time

I hope it was useful, and you're better equipped to use pattern matching to the fullest! I've just started writing here and on the Rock the JVM blog, so leave your feedback in the comments, I read everything.

If you liked this, you can also read the 2-hour Scala at Light Speed comprehensive mini-series on Scala and functional programming.

Scala (programming language)

Published at DZone with permission of Daniel Ciocirlan. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Thermometer Continuation in Scala
  • Deploying a Scala Play Application to Heroku: A Step-by-Step Guide
  • Upgrading Spark Pipelines Code: A Comprehensive Guide
  • Java vs. Scala: Comparative Analysis for Backend Development in Fintech

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!