I am current brainstorming and researching the best way to do explicit error handling in scala.

Ideal end product:

Compiler enforce that you have checked all (explicitly stated) errors

As little boilerplate as possible

No or little additional runtime cost (which means no parent type of all possible errors from all functions)

Allows you to be both explicit and implicit in stating

Basically, I want checked exceptions on steriods.

Ignoring exception throwing, the typical way to handle this is to use the Either type (or \/ from Scalaz, which I'm using) and have the left side to be an ADT containing all possible errors like this:

sealed trait Error_parseAndValidate case class ParseError(msg: String) extends Error_parseAndValidate case class ValidateError(msg: String) extends Error_parseAndValidate def parseAndValidate(str: String): Error_parseAndValidate \/ Int = { // can return ParseError or ValidateError }

However this gets really tedious if your function call nests multiple levels:

Consider this DB example with the following call stack

main -> getResultWithString -> parseAndValidate / fetchResultFromDB

// error type ADT containing expected errors in parseAndValidate // similarly for other error_* traits sealed trait Error_parseAndValidate case class ParseError(msg: String) extends Error_parseAndValidate case class ValidateError(msg: String) extends Error_parseAndValidate def parseAndValidate(str: String): Error_parseAndValidate \/ Int = { // can return ParseError or ValidateError } sealed trait Error_fetchResultFromDB case class DBError(msg: String) extends Error_fetchResultFromDB def fetchResultFromDB(lookupId: Int): Error_fetchResultFromDB \/ Result = { // can return DBError } sealed trait Error_getResultWithString case class ErrorFromFetchResult(Error_fetchResultFromDB) extends Error_getResultWithString case class ErrorFromParseValidate(Error_parseAndValidate) extends Error_getReusltWithString def getResultWithString(input: String): Error_getResultWithString \/ Result = { } // we need to 'extract/unwrap' our error type. this is tedious! def main() = { getResultWithString.leftMap { case ErrorFromFetchResult(e) => e match { case ParseError => case ValidateError => } case ErrorFromParseValidate(e) => e match { case DBERror => } } }

Though we achieved correctness, this is tedious especially when you have more than 3-4 level of call stack!

What I am envisioning is an extensible disjunction type which will allow us to 'extend' our errors. It feels like something in shapelss might be able to help me achieve this, but have not used it in the past and I don't think HList is the right tool for this situation.

This is what I have been envisioning:

I am using | symbol here to represent disjunction (union) here between two types. The most important thing here is that we no longer need to wrap and unwrap our errors using ADT -- The Error we finally match on is just a **flat disjunction*.

// you can see here we are simply 'joining' the errors from both method calls, // instead of wrapping it in a ADT which requires unwrapping def getResultWithString(input: String): Error_parseAndValidate|Error_fetchResultFromDB \/ Result = { for { lookupId <- parseAndValidate(input) result <- fetchResultFromDB(lookupId) } yield result } type Error_parseAndValidate = ParseError | ValidateError def parseAndValidate(input: String): Error_parseAndValidate \/ Int = { //returns ParseError or ValidationError } type Error_fetchResultFromDB = DBError def fetchResultFromDB(lookupId: Int): Error_fetchResultFromDB \/ Result = { //returns DBError } def main() = { getResultWithString("bad string").leftMap { case ParseError => //... case ValidateError => //... case DBError => //... } }

The answers from this SO question have some solutions, however the solutions are not extensible.

My question

Is it possible to achieve what I'm envioning in scala?