If you’ve gotten this far reading my blog, you’re probably very familiar with `Either`. Of course Im also assuming someone is reading this blog in the first place 😛

Anyway, `Either[A,B]` allows us to return either an `A` or a `B` depending on some conditions… In other words, its a XOR (exclusive or) A value can either be A or it can be B but it cannot be both.

You probably see where this is going, `IOR` is a cats datatype that stands for Inclusive Or. In other words, `Ior[A,B]` can either be `A` or it can be `B` or it can be `Both A and B`.

Another syntax for defining an Ior is: `A Ior B`

Ior is often used when we want to handle errors and correct values as well as correct values but wth a warning.

## Examples

Here is an example using IOR:

``````  import cats.data.Ior

val right: Ior[String, Int] = Ior.right[String, Int](3)
val left: Ior[String, Int] = Ior.left[String, Int]("Error")
val both: Ior[String, Int] = Ior.both[String, Int]("Warning", 0)``````

Of course things can be made to look nicer when using the cats syntax:

``````  import cats.syntax.ior._

val x: Ior[String, Nothing] = "NOPE".leftIor
// Or
val z: Ior[String, Int] = "Better Nope".leftIor[Int]``````

## Accumulating Errors

Another benefit of Ior is its ability to accumulate errors on the left side. Similar to Cats Validated (Will be discussed in a later article)

### How does it work

Ior will accumulate warnings on the left side but will short circuit the computations as soon as it encounters a left only value. Lets look at an example for a clearer image.

``````  import cats.data.Ior
import cats.syntax.ior._
import cats.data.{NonEmptyList => Nel}
type Failures = Nel[String]

final case class UserName(private val name: String) extends AnyVal {

if (name.isEmpty) Nel.one("Error, Username cannot be empty").leftIor
Ior.both(
Nel.one(
"In the future, protected words will no longer be considered valid"),
}
}

final case class UserPassword(private val value: String) extends AnyVal {
if (value.isEmpty) Nel.one("Passwords cannot be empty").leftIor
else if (value.length < 10)
}
}``````

which would allow us to create a valid `User`:

Note: If you’re confused by mapN and the various imports, it’ll be explained in another post along with validated and validatedN.

``````  import cats.syntax.apply._

``````  val username2 = UserName("admin")

This is what we meant by accumulating warnings or nonblocking errors.

But what if we encountered a blocking error?

``````  val username3 = UserName("")

//user3 ==> Left(NonEmptyList(Error, Username cannot be empty))``````

Notice it short circuited the computations without accumulating the errors on the left side (Password was empty but the error was not added to that of Username)

## Conversion

Ior Can be converted to an `Either` a `Validate` or even an `Option`.

Keep in mind however that when doing so, the `Both` will drop its left side and only keep the right value and transform it to a `Some` or a `Right` ect…

Here are the transformation codes:

``````  final def toEither: Either[A, B] = fold(Left(_), Right(_), (_, b) => Right(b))
final def toValidated: Validated[A, B] = fold(Invalid(_), Valid(_), (_, b) => Valid(b))
final def toOption: Option[B] = fold(_ => None, b => Some(b), (_, b) => Some(b))``````