Exceptions

Error handling

The C way to do error handling is usually via return codes:

openFile: (path: String) -> Int {
  if (error) {
    return -1
  }
  return someFileDescriptor
}

However, it relies on the user correctly checking the return value:

fd := openFile("/etc/hosts")
doSomethingWithFile(fd) // forgot to check, things might go bad!

Exceptions

raise

Another way to handle that would be with exceptions

openFile: (path: String) -> File {
  if (error) {
    raise("Could not open %s" format(path))
  }
  return someFile
}

That way, even if the user doesn’t explicitly check for the error, it’ll still interrupt the flow of the program:

file := openFile("/dev/does/not/exist")
doSomethingWithFile(file) // we are never even going to reach there

Throwing

The raise function above is a quick method to raise an exception. What it really does is this:

Exception new(message) throw()

There is no special keyword to throw exceptions, it’s just a method on the Exception class.

Catching exceptions

Catching exceptions is done through the try / catch syntax:

try {
  openFile("dev/does/not/exist")
} catch (e: Exception) {
  // something wrong happened
  "Error: #{e message}" println()
}

Exception sub-classes

It is possible to sub-class exceptions to have several exception types.

FileNotFoundException: class extends Exception {
  init: func (path: String) {
    super("File not found: %s" format(path))
  }
}

openFile: func (path: String) {
  if (error) {
    FileNotFoundException new(path) throw()
  }
}

Which makes it easy to catch a specific type of exception:

try {
  file := openFile("/dev/does/not/exist")
  doSomethingWithFile(file)
} catch (e1: FileNotFoundException) {
  // The file wasn't found
} catch (e2: Exception) {
  // Something else went wrong.
}