Exceptions
Throwing exceptions
Crow supports exceptions in a similar way to other languages.
throw takes an exception argument.
exception is a variant type and error is a
variant-member of it.
(For a refresher: Variants)
throw is an expression that can provide any expected type.
"Assert" and "Forbid"
In most cases an exception is not thrown unconditionally.
assert and forbid
are shorthand for conditionally throwing exceptions.
assert throws an exception if its condition is false,
and forbid throws if its condition is true.
By default, these throw error exceptions.
A custom exception can be written after a :.
Like a guard, an assert can take an option condition.
The unwrapped option is available below the assert, otherwise an error is thrown.
forbid can also take an option condition,
and the unwrapped value is available in the exception expression.
Catching exceptions
You can also catch exceptions.
Just like for an if, both branches of the
try expression should return the same type,
in this case string.
The catch works like an as in a
match, where the thing being matched is the exception.
You can have multiple catch handlers for different possible exceptions.
If there is no exception or the exception does not match the expected
variant-member, the catch has no effect.
There is a minor issue above: The try wraps both the division
and the conversion to a string.
Often you want precise control over exactly which expression has its exceptions caught.
To make that more convenient, you can combine try and
=:
Above, exceptions will only be caught in 1 / 0, not in anything below.
Like a guard, this has two branches:
A success branch below and an error branch to the right.
It's asymmetric since the error branch is generally shorter and less important.
As with a guard,
the : branch is optional and defaults to ().
So the below will not log anything.
Defining an exception type
Since exception is just a variant,
a custom exception is a variant-member.
"Finally"
Crow supports a "finally" expression that works like in other languages, but with different syntax.
It is a single line, where the argument to finally runs after
the code below it (regardless of whether the below code throws an exception).
The reason it's done this way is that typically finally
is used to clean something up, so it's best to put it right after the thing it cleans up
to be sure you don't forget.
Catching all exceptions
There's no syntax for this, but there is a catch-all function.
It returns a (t, exception-and-backtrace) result. More details in exception.
You normally don't need to call this as you could just rely on the default exception handler. But this would give you the opportunity to format your own custom exceptions.