Custom Errors in Scala

import scala.util.{Try, Success, Failure}

// A custom error type usually has the suffix "Error".
case class ArgError(arg: Int, message: String) extends Exception(s"$arg - $message")

def f(arg: Int): Try[Int] = {
  if (arg == 42) {
    // Return our custom error.
    Failure(ArgError(arg, "can't work with it"))
  } else {
    Success(arg + 3)
  }
}

def main(args: Array[String]): Unit = {
  // In Scala, we use pattern matching to handle different types of errors
  f(42) match {
    case Failure(ae: ArgError) =>
      println(ae.arg)
      println(ae.message)
    case _ =>
      println("err doesn't match ArgError")
  }
}

In this Scala version, we’ve made several changes to adapt the code to Scala’s idioms and error handling mechanisms:

  1. We’ve defined ArgError as a case class that extends Exception. This is a common way to create custom exceptions in Scala.

  2. Instead of returning a tuple of (int, error), we use Scala’s Try type. Try[Int] can be either a Success[Int] or a Failure[Throwable].

  3. In the f function, we return Failure(ArgError(...)) instead of returning a tuple with an error.

  4. In the main function, we use pattern matching to check if the result is a Failure containing an ArgError. This is similar to the errors.As function in the original code.

To run this program:

$ scala custom_errors.scala
42
can't work with it

In Scala, we don’t typically compile to standalone binaries. Instead, we usually package our code into JAR files and run them using the Scala runtime. However, there are tools like sbt-native-packager that can create standalone distributions if needed.

This example demonstrates how to create and use custom error types in Scala, and how to use Scala’s Try type and pattern matching for error handling.