How can I manage error states that may be shared across multiple type hierarchies?
Consider an application that manages a database of people. It has a Person model and two methods in the API:
case class Person(name: String)
def createPerson(name: String): Either[CreateFailure, Person]
def renamePerson(newName: String): Either[RenameFailure, Person]
sealed trait CreateFailure
object CreateFailure {
case object PersonAlreadyExists extends CreateFailure
case object NamesCantHaveEmojis extends CreateFailure
}
sealed trait RenameFailure
object RenameFailure {
case object CanOnlyRenameMinors extends RenameFailure
case object NamesCantHaveEmojis extends RenameFailure
}
Each method can fail in its own unique way, but each method can also fail in the same way via NamesCantHaveEmojis. In the above trivial example I have two copies of this error state and this is triggering my code smell sensors. What if I need extend NamesCantHaveEmojis with new functionality, do I add it to both? Or have them each implement a common trait EmojiUtils that provides the shared functionality?
Scala 3's Union Types seem like they would fit the bill, but we haven't adopted Scala 3 yet.
type CreateFailure = PersonAlreadyExists | NamesCantHaveEmojis
type RenameFailure = CanOnlyRenameMinors | NamesCantHaveEmojis
It seems like many folks in the Scala community have been using Either for explicit error handling for a while now so I can only assume someone else has come across this scenario and found a good solution.
How can I share error states across multiple type hierarchies in Scala 2?