This guide is only about User-Exceptions
- System-Errors
are usually fatal
and should never be caught.
A common case for exceptions is to validate potentially invalid user input. Once an exception is thrown, the stack will be unwound until the first matching exception handler is found.
try
{
readText("dummyFile");
}
catch (FileException e)
{
// ...
}
It's possible to have multiple catch
blocks and a finally
block that is executed
regardless of whether an error occurred. Exceptions are thrown with throw
.
try
{
throw new StringException("You shall not pass.");
}
catch (FileException e)
{
// ...
}
catch (StringException e)
{
// ...
}
finally
{
// ...
}
Remember that the scope guard is usually a better solution to the try-finally
pattern.
One can easily inherit from Exception
and create custom exceptions:
class UserNotFoundException : Exception
{
this(string msg, string file = __FILE__, size_t line = __LINE__) {
super(msg, file, line);
}
}
throw new UserNotFoundException("D-Man is on vacation");
nothrow
The D compiler can ensure that a function can't cause catastrophic side-effects.
Such functions can be annotated with the nothrow
keyword. The D compiler
statically forbids throwing exceptions in nothrow
functions.
bool lessThan(int a, int b) nothrow
{
writeln("unsafe world"); // output can throw exceptions, thus this is forbidden
return a < b;
}
Please note that the compiler is able to infer attributes for templated code automatically.
It is important to avoid assert
and the soon to be introduced
contract programming
for user-input as assert
and contracts
are removed when compiled in release mode. For convenience
std.exception
provides
enforce
that can be used like assert
, but throws Exception
s
instead of an AssertError
.
import std.exception : enforce;
float magic = 1_000_000_000;
enforce(magic + 42 - magic == 42, "Floating-point math is fun");
// throw custom exceptions
enforce!StringException('a' != 'A', "Case-sensitive algorithm");
However there's more in std.exception
. For example when the error might not be
fatal, one can opt-in to
collect it:
import std.exception : collectException;
auto e = collectException(aDangerousOperation());
if (e)
writeln("The dangerous operation failed with ", e);
To test whether an exception is thrown in tests, use assertThrown
.