Errors and exceptions

Declare exceptions, throw them, and catch them with try, catch and finally in Antril.

Last updated 4 min read Edit on GitHub

On this page

Errors are reported by throwing an exception: an object of a class derived from System.Exception. The nearest try with a matching catch handles it.

AntrilRun
import System;

into namespace Bank
{
	public exception InsufficientFunds
	{
		public:
			i32 Missing;

			new(i32 missing) : base("insufficient funds")
			{
				Missing = missing;
			}
	}

	Withdraw(i32 balance, i32 amount) : i32
	{
		if (amount > balance)
			throw new InsufficientFundsException(amount - balance);
		return balance - amount;
	}

	Main()
	{
		try
		{
			Console.WriteLine(Withdraw(30, 10));
			Console.WriteLine(Withdraw(10, 25));
		}
		catch (InsufficientFundsException e)
		{
			Console.WriteLine(e.Message + ": " + e.Missing + " missing");
		}
		finally
		{
			Console.WriteLine("done");
		}
	}
}
Terminal
larva run
20
insufficient funds: 15 missing
done

Declaring exceptions

exception Name { … } declares the class NameException, derived from System.Exception. The suffix is added for you, and you throw and catch it by its full name. Its base can be another exception, written without the suffix:

Antril
public exception NotFound
{
	public:
		new(str message) : base(message) { }
}

public exception FileNotFound : NotFound
{
	public:
		new(str path) : base("no file " + path) { }
}

throw new FileNotFoundException("notes.txt");

System.Exception has a Message. A class can also derive from Exception directly.

Throwing

throw value; throws an exception object. Inside a catch, throw; throws the same exception again.

A generic function can throw a type parameter constrained with T : exception.

Catching

AntrilRun
import System;

Main()
{
	try
	{
		List<i32> empty = new List<i32>();
		empty.At(3);
	}
	catch (IndexError e)
	{
		Console.WriteLine("IndexError: " + e.Message);
	}

	try
	{
		Int32.Parse("x1");
	}
	catch
	{
		Console.WriteLine("something failed");
	}

	try
	{
		try
		{
			throw new InvalidOperationError("inner");
		}
		catch (Exception e)
		{
			Console.WriteLine("logging " + e.Message);
			throw;
		}
	}
	catch (InvalidOperationError e)
	{
		Console.WriteLine("handled " + e.Message);
	}
}
Terminal
larva run
IndexError: the index is outside the collection
something failed
logging inner
handled inner
  • catch (T e) handles exceptions of type T and of the types derived from it. The name can be left out: catch (KeyNotFoundError).
  • catch alone handles any exception.
  • catch clauses are tried in order.
  • finally runs when the try ends, whichever way it ends: normally, by an exception, or by return, break or continue.

An exception thrown inside an async function travels in its task, and await throws it again (see Async and reactive code).

Exceptions of the standard library

Exception Thrown when
ArgumentError, ArgumentOutOfRangeError An argument is not one the method takes.
IndexError An index is outside a collection.
KeyNotFoundError A dictionary does not have the key.
InvalidOperationError The object is not in a state that allows the operation, such as Dequeue or Peek on an empty queue.
OverflowError A result does not fit its type.
FormatError Text cannot be parsed (Int32.Parse("x")).
IOError A file, folder or stream operation fails (System.IO).

Uncaught exceptions

An exception that no catch handles ends the program with exit code 1:

Terminal
larva run
larva: unhandled exception (type id 461533486)

Next: Memory.

Was this page helpful?

No address is stored; your user name is, if you are signed in.

Esc