Errors

In Asylum, you can return an error instead of a normal value in a function if things do not go according to plan. For example:

fn safeDiv(int a, int b) -> int?
{
    if (b == 0)
        return Err();
    else
        return Ok(a / b);
}

fn main()
{
    int? a = safeDiv(5, 3);
    int? b = safeDiv(2, 0);
    if (a) {
        println(+a);
    } else {
        println(0):
    }
    match (b) {
        Err:
            println(0);
        Ok(val):
            println(val):
    }
}

Output:

1
0

The above code will catch a division by zero before it happens. It is important to note that T? is actually a shortcut for Res<T, void>, so any optional type is actually a result enum! This is why we are allowed to return Err and Ok in safeDiv and can use the match statement in main. Note that the code for checking a and b do the same thing. This is because Res can be implicitly casted to a boolean, where it is true only if there is no error present. Using + on a result will return its valid value. Using + when an error is present will abort the program and dump a stack trace in debug mode, but will result in undefined behavior in release mode.

Error Types

Results can specify types for errors as well other than the default void for optionals. This allows you to provide more detail about the error encountered. For example, you can return an error message instead:

fn safeDiv(int a, int b) -> Res<int, str>
{
    if (b == 0)
        return Err("Division by 0 attempt.");
    else
        return Ok(a / b);
}

fn main()
{
    Res<int, str> a = safeDiv(5, 3);
    Res<int, str> b = safeDiv(2, 0);
    if (a)
        println(+a);
    else
        println(-a):
    match (b) {
        Err(err):
            println(err);
        Ok(val):
            println(val):
    }
}

Output:

1
Division by 0 attempt.

Using - is similar to using + on a result with the exception that using - will give the error of a result, assuming it is valid. If it is not valid, the program will be aborted with a stack trace dumped in debug mode or result in undefined behavior in release mode.

False Operator

If you wish to have a default value even if a function returns an error, there is a special usage of the ?? (false operator) in which an error will be treated as “false”.

fn main()
{
    int a = safeDiv(5, 3) ?? 0;
    int b = safeDiv(2, 0) ?? 0;
    println(a);
    println(b);
}

Output:

1
0

For results, you can think of a ?? b as doing the following where a is Res<T, U> and b is T:

a ? (+a) : b;

Essentially, the value is returned from the result if it exists or an alternative value is returned instead. Notice that the usage of this operator in main allows you to do the same thing as the main before but with less syntax!

Error Propagation

Sometimes you would like to exit a function early when an error is encountered. The !? (success or die) operator is for this purpose: it will either dereference the value from the result or return the error’d result if the result is an error.

fn safeDiv(int a, int b) -> int?
{
    if (b == 0)
        return Err();
    else
        return Ok(a / b);
}

fn safeAddDivs(int a, int b) -> int?
{
    int div1 = safeDiv(a, b)!?;
    int div2 = safeDiv(b, a)!?;
    return Ok(div1 + div2);
}

fn main()
{
    println(safeAddDivs(3, 5));
    println(safeAddDivs(0, 2));
}

Output:

Ok(1)
Err()

Though it’s important to note that the result type of safeAddDivs and safeDiv must match. If you wish to return a different result or error you can do so by putting it after the operator:

fn safeDiv(int a, int b) -> int?
{
    if (b == 0)
        return Err();
    else
        return Ok(a / b);
}

fn safeAddDivs(int a, int b) -> Res<int, str>
{
    int div1 = safeDiv(a, b) !? Err("Division by 0");
    int div2 = safeDiv(b, a) !? Err("Division by 0");
    return Ok(div1 + div2);
}

fn main()
{
    println(safeAddDivs(3, 5));
    println(safeAddDivs(0, 2));
}

Output:

Ok(1)
Err(Division by 0)

While here the !? operator is used to return errors immediately, it could also return valid results if you wanted to! Overall, these operators help you write cleaner and denser code.

Challenges

TODO!!!

Challenge Solutions

TODO!!!