Four new features of Scala 2.13 releases that you probably missed
Do you know this feeling when a coworker suggests a change under your pull request, that you didn't know that is possible in scala? I am more than familiar with this feeling. That's why I decided to check the release notes for all 2.13 releases and decided to share my findings
2.13.0 s
interpolator on pattern matching
There are some moments when you need to parse a simple string. Writing a fully-fledged regular expression can be time-consuming and leaves some maintainability burden. Fortunately for us, starting from 2.13.0 you can use quite a handy pattern matching on strings
def getMonth(date: String): Option[String] = date match{
case s"$_-$month-$_" => Some(month)
case s"$month/$_/$_" => Some(month)
case _ => None
}
If you are curious how is it implemented, check the pull request
2.13.0 toXOption
Before the 2.13 release whenever you wanted to parse a string into int you needed to use .toInt
on a string. Unfortunately, you needed to wrap the call with some effect type since it throws NumberFormatException
on inputs which cannot be parsed.
A set of very handy methods was added in 2.13. You can use toIntOption
which returns None
in case of input that cannot be parsed. Of course, there is more than just int parsing, the whole family of toX
function now have the toXOption
counterparts. Check the whole list here and the original pull request here.
2.13.0 Pipe and tap
You can find piping syntax in languages like Bash, F#, OCaml, and ReasonML. It can be used to chain transformations of data like this:
cat production.log | grep 'ERROR' | wc -l
2.13.0 version of scala made it possible for you. If you import import scala.util.chaining._
you can use pipe and tap syntax. Pipe is used to evaluate a function and tap is used to investigate the value.
import scala.util.chaining._
5.pipe(_ * 5)
.tap(println)
.pipe(_ + 1)
The example above prints 25 and returns 26.
The implementation details can be found in the original pull request.
2.13.4 Exhaustivity checks with if guards
Let's suppose you have the following piece of code
case class Temperature(value: Int)
def aFunction(temperature: Temperature) = temperature match {
case Temperature(value) if value > 0 => println("over 0")
}
It compiles, but when you try to run it with temperature <= 0 you end with MatchError
. You might ask how is it possible, isn't the compiler responsible for exhaustivity check in pattern matching? It is, but before scala 2.13.4 using guard expressions was turning off the check the issue on github.
Starting from 2.13.4 compiler checks the exhaustivity by assuming false returned by every guard so
def aFunction(temperature: Temperature) = temperature match {
case Temperature(value) if value > 0 => println("over 0")
case Temperature(value) if value <= 0 => println("lower or equal 0")
}
This will still raise a warning match may not be exhaustive.
To fix it we need a default case
def aFunction(temperature: Temperature) = temperature match {
case Temperature(value) if value > 0 => println("over 0")
case Temperature(value) if value <= 0 => println("lower or equal 0")
case _ => println("default")
}
You can still remove the exhaustivity check with @unchecked
annotation.
For more information on this check the original pull request
Summary
I hope that after reading this article you could be the one that proposes to use new, nice scala features to your coworkers.