## 1. Introduction

In this tutorial, we will be looking at partial functions in Scala. **A partial function is a function applicable to a subset of the data it has been defined for.**

For example, we could define a function on the *Int* domain that only works on odd numbers.

## 2. Understanding the Definition

If we look at the Scaladoc definition, there are three main characteristics to highlight.

A partial function:

**is a unary operation**, which means it only takes one parameter**is applicable to a subdomain of values****can**explicitly**include an**, to define its domain,*isDefinedAt*method**and an**method*apply*

Let’s have a look at an example of a partial function:

```
val squareRoot: PartialFunction[Double, Double] = {
def apply(x: Double) = Math.sqrt(x)
def isDefinedAt(x: Double) = x >= 0
}
```

Analyzing the above function, we can see that it:

- takes a single parameter, a
*Double* - applies to a
*Double*subdomain, such as*x >= 0* - has an
*isDefinedAt*method and an*apply*method

Therefore, it is indeed a partial function.

** isDefinedAt and apply are often implicitly defined**. We can rewrite our function using a

*case*statement. It’s a really common practice when writing partial functions:

```
val squareRootImplicit: PartialFunction[Double, Double] = {
case x if x >= 0 => Math.sqrt(x)
}
```

Invoking our partial function on a negative number will return a *scala.MatchError* runtime error.

## 3. Chaining With *orElse* and *andThen*

Chaining is a very useful feature of partial functions.

Let’s say we want to convert positive integers to negative and vice-versa. Clearly, just multiplying by the integer *-1* would do the trick.

However, to demonstrate the chaining feature, our solution will include:

- If the number is negative or zero, then return its absolute value
- If the number is positive, then return the number multiplied by
*-1*

Therefore, **we can define a partial function for each requirement**:

```
val negativeOrZeroToPositive: PartialFunction[Int, Int] = {
case x if x <= 0 => Math.abs(x)
}
val positiveToNegative: PartialFunction[Int, Int] = {
case x if x > 0 => -1 * x
}
```

**Then we can leverage the chaining operator orElse to use them together:**

```
val swapSign: PartialFunction[Int, Int] = {
positiveToNegative orElse negativeOrZeroToPositive
}
```

Additionally, **the PartialFunction trait also includes andThen**

*.*As a result, chaining is really easy to achieve.

To show how *andThen* works, let’s begin with a function that only prints positive *Int* values:

```
val printIfPositive: PartialFunction[Int, Unit] = {
case x if x > 0 => println(s"$x is positive!")
}
```

We can now chain this with our *swapSign* function:

`(swapSign andThen printIfPositive)(-1)`

The final result is easy-to-chain code that reads quite nicely.

## 4. Working With Collections

When working with collections, there are several methods that are well-suited for partial functions.

Let’s have a look at some of the main ones, behaving in a not-so-obvious way.

### 4.1. *collect, map, and filter*

*collect *is a method that, given a collection, will return a new collection by applying a partial function to the elements in its domain.

Let’s define a partial function to be used by the *collect* method:

```
val parseRange: PartialFunction[Int, Int] = {
case x: Int if x > 10 => x + 1
}
List(15, 3, "aString") collect { parseRange }
```

Our partial function will only be applied to *15* since it is the only *Int* greater than *10* in our *List*.

Therefore, the above will return *List(16).*

**We can use parseRange with map as well**, without creating any compilation error:

`List(15, 3, "aString") map { parseRange }`

**This code will throw a scala.MatchError at runtime** because the pattern match doesn’t know how to handle a

*String*.

The last method we’ll look at is *filter*, which is similar to *collect, *except* filter *returns a collection of elements that satisfy a provided condition.

We can see the different results returned using the same partial function to show that **the collect and filter methods behave differently**:

```
List(1, 2) collect { case i: Int => i > 10 }
List(1, 2) filter { case i: Int => i > 10 }
```

In this case, *collect* returns *List(false, false)*, while *filter* returns an empty list. Also, notice how we defined the partial function as an anonymous function.

## 5. Conclusion

In this article, we looked at partial functions. We showed that chaining partial functions and using them with collection methods is pretty straightforward.

Whenever we’re aiming for highly composable code, partial functions are definitely something to keep in mind. When used with collections in particular, methods like *collect*, *map,* and *filter* make data manipulation and transformation easy.

The combination of these characteristics makes partial functions a powerful tool.

As always, the code is available over on GitHub.