Hare by Example: Custom Errors

Hare lets you define your own error types and leverage tagged unions to define a generic module error of all possible errors to make handling them easier.

use errors;
use fmt;

// Something got flubbed error
type flubbed = !void;

// Something derped error
type derpped = !void;

// Tagged union of all possible errors along with our custom errors
// so we can use this error in our functions returns.
type error = !(...errors::error | flubbed | derpped);

// It is good practice to offer a strerror() function that matching on
// all of your possible error type and returns a human-friendly version
// of it. Since we also have the tagged union with errors::error we
// default to that module's strerror() function to handle those strings.
fn strerror(err: error) str = {
	match (err) {
	case flubbed =>
		return "flubbed occured";
	case derpped =>
		return "derpped occured";
	case let err: errors::error =>
		return errors::strerror(err);
	};
};

// If a is less than 0 then this returns a flubbed error.
fn add(a: int, b: int) (int | flubbed) = {
	if (a < 0) {
		return flubbed;
	};

	return a + b;
};

// If b is less than 0 then this returns a derpped error.
fn mul(a: int, b: int) (int | derpped) = {
	if (b < 0) {
		return derpped;
	};

	return a * b;
};

// calc attempts to add and mul the args and propgate any error up.
// Since our local error type is in the return which can be flubbed or
// derpped this is allowed.
fn calc(a: int, b: int) (int | error) = {
	let a = add(a, b)?;
	let m = mul(a, b)?;

	return a + b;
};

export fn main() void = {
	// We know this will not error so we can assert ! just fine
	let a = add(1, 1)!;
	fmt::println(a)!;

	// We know this will not error so we can assert ! just fine
	let m = mul(5, 5)!;
	fmt::println(m)!;

	// Since -1 will cause add() to error with flubbed we'll catch
	// this in the first case even though calc returns the general
	// error type.
	let c = match (calc(-1, 100)) {
	case let err: flubbed =>
		fmt::printf("our error str: {}", strerror(err))!;
	case let err: derpped =>
		fmt::printf("our error str: {}", strerror(err))!;
	case let result: int =>
		yield result;
	};
};
$ hare run custom-errors.ha
4/4 tasks completed (100%)
2
25
our error str: flubbed occured