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.