# Handling function partiality

Consider the following snippet:

def isqrt_option(num: Int): Option[Int] = {
num match {
case x if x >= 0 => Some(math.sqrt(x).toInt)
case _ => None
}
}

Conceptually, isqrt_option is a partial function from natural numbers to natural numbers that returns square root of its input rounded down. It has a particular flavour of partiality as I will explain soon.

## Flavours of partiality - the callee side

There are many ways to implement a partial function. We have already seen how we can use Optional return values to implement partiality. We can similarly use Either:

final case object NegativeInputArgument(value: Int)

def isqrt_either(num: Int): Either[NegativeInputArgument, Int] = {
num match {
case x if x >= 0 => Right(math.sqrt(x).toInt)
case x => Left(NegativeInputArgument(x))
}
}

Sometimes you want to use an assertion instead because of some really complex type refinement (e.g. inter-dependency between multiple input data structures), that would be difficult to express in types without a dependently typed language (or even then!):

/**
* @param num non-negative integer
*/
def isqrt_assert(num: Int): Int = {
assert(num >= 0)
math.sqrt(x).toInt
}

Alternatively, we can use type refinements (using refined Scala library or something similar).

final case class NonNegInt private (value: Int) {
assert(num.value >= 0)
}
object NonNegInt {
def refine(i: Int): Option[NonNegInt] =
if (i > 0) Some(NonNegInt(i))
else None

// A macro would allow us to specify literal non-negative integers.
implicit def literal(x: Int): NonNegInt = macro applyImpl
}

def isqrt_refined(num: NonNegInt): Int =
math.sqrt(num.value).toInt

## The caller side

Imagine that a caller of isqrt function has already verified that num is positive:

val num = ...
if (num > 0) {
...
val r = isqrt_option(num)
r match {
case Some(x) => ...
case None =>
// OOPS, what do we do here?
}
}

We can see that using Optional return values just moves partiality to the call-site. The problem is that even though we know that num > 0, most modern compilers are not able to infer that the None case is impossible (the only exception that I know of is Code Contracts for C#, which has some very similar functionality).

Let’s see how the same code would look like if we used isqrt_assert:

val num = ...
if (num > 0) {
...
val r = isqrt_assert(num)
// No need to match on r, it's already an Int.
...
}

Notice that this coding style will necessarily result in some runtime failures due to your logical errors (which are bound to happen sooner or later!), but it is mighty convenient.

Using the refinement-based solution:

val num = ...
NonNegInt.refine(num) match {
case Some(num) =>
...
val r = isqrt_refined(num)
// No need to match on r, it's already an Int.
...
case None =>
...
}

Beautiful. But… what if we wanted to compute a square root of a square root?

val r = isqrt_refined(num)
val r1 = isqrt_refined(r) // OOPS, doesn't compile
}

We have to modify the definition of isqrt_refined:

def isqrt_refined(num: NonNegInt): NonNegInt =
NonNegInt.make(math.sqrt(num.value).toInt) match {
case Some(n) => n
case None => ???
}

With a better compiler or language perhaps this could have been avoided, but sooner or later, the asserts will creep back in into your code. In dependently typed languages that will happen when you are just too tired to prove some property of your code, so you invoke believe_me. And no matter how good a compiler is, the halting problem will prevent it from proving all of potential code properties (but it could still have insanely large coverage, being able to say prove 99.999999% of all properties).

Don’t hate the assert, it is your friend! You just need to learn to use it in a tasteful way.