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.