ZIO.fromOption returns Option[Nothing]; what is that? (Unit? None?)

I noticed that the ZIO 2 ZIO.fromOption method returns Option[Nothing] as its error type, so I asked my friend Claude about it, and got the following response, which I have cleaned up a little.

Solution

When you look at the signature of ZIO.fromOption, you’ll see something like this:

def fromOption[A](option: Option[A]): ZIO[Any, Option[Nothing], A]

Let’s break this down:

  1. Option[Nothing] as the error type:

  • As I wrote about in What is the Scala Nothing type?, Nothing is a special type in Scala. It’s a subtype of every other type and has no instances. It’s often used to represent computations that don’t return normally (like throwing an exception or an infinite loop).

  • Option[Nothing] is effectively equivalent to None. Since Nothing has no instances, the only possible value of Option[Nothing] is None.

  1. Why use Option[Nothing] instead of just Unit?

  • Using Option[Nothing] as the error type allows ZIO to preserve the semantic information that the failure came from an empty Option.

  • It also allows for more precise type inference in certain scenarios.

  1. Practical implications:

  • When you use ZIO.fromOption, the resulting ZIO effect will fail with None if the original Option was None.

  • This is why we often need to map this error to a more meaningful error type in our applications, as we did in our optionToZIO function.

Example

Here’s a small example to illustrate:

val someOption: Option[Int] = Some(42)
val noneOption: Option[Int] = None

val zioFromSome: ZIO[Any, Option[Nothing], Int] = ZIO.fromOption(someOption)
val zioFromNone: ZIO[Any, Option[Nothing], Int] = ZIO.fromOption(noneOption)

// Usage:
zioFromSome.foldZIO(
    error => ZIO.succeed(s"This won’t be called"),
    success => ZIO.succeed(s"Got value: $success")
)

zioFromNone.foldZIO(
    error => ZIO.succeed(s"Failed with: $error"), // This will print "Failed with: None"
    success => ZIO.succeed(s"This won’t be called")
)

Discussion

In practice, when working with ZIO.fromOption, we often want to map this Option[Nothing] error to a more specific error type, which is exactly what your convertOptionToZIO function does:

def convertOptionToZIO[A, E](option: Option[A], error: => E): ZIO[Any, E, A] =
    ZIO.fromOption(option)
       .orElseFail(error)   //mapError

This use of Option[Nothing] is a good example of how Scala’s type system and ZIO work together to provide both type safety and expressive power. It allows ZIO to represent the concept of “absence of value” from Option in its error channel, while still giving us the flexibility to map it to more specific error types as needed.