This module defines functions related to exceptions and general error handling. It also defines functions intended to aid in unit testing.
Category | Functions |
---|---|
Assumptions | assertNotThrown assertThrown assumeUnique assumeWontThrow mayPointTo |
Enforce | doesPointTo enforce enforceEx errnoEnforce |
Handlers | collectException collectExceptionMsg ifThrown handle |
Other | basicExceptionCtors emptyExceptionMsg ErrnoException RangePrimitive |
exception
's functions: string synopsis() { FILE* f = enforce(fopen("some/file")); // f is not null from here on FILE* g = enforce!WriteException(fopen("some/other/file", "w")); // g is not null from here on Exception e = collectException(write(g, readln(f))); if (e) { ... an exception occurred... ... We have the exception to play around with... } string msg = collectExceptionMsg(write(g, readln(f))); if (msg) { ... an exception occurred... ... We have the message from the exception but not the exception... } char[] line; enforce(readln(f, line)); return assumeUnique(line); }
Asserts that the given expression
does not throw the given type of Throwable
. If a Throwable
of the given type is thrown, it is caught and does not escape assertNotThrown
. Rather, an AssertError
is thrown. However, any other Throwable
s will escape.
T | The Throwable to test for. |
E expression
| The expression to test. |
string msg
| Optional message to output on test failure. If msg is empty, and the thrown exception has a non-empty msg field, the exception's msg field will be output on test failure. |
string file
| The file where the error occurred. Defaults to __FILE__ . |
size_t line
| The line where the error occurred. Defaults to __LINE__ . |
AssertError
if the given Throwable
is thrown. expression
.import core.exception : AssertError; import std.string; assertNotThrown!StringException(enforce!StringException(true, "Error!")); //Exception is the default. assertNotThrown(enforce!StringException(true, "Error!")); assert(collectExceptionMsg!AssertError(assertNotThrown!StringException( enforce!StringException(false, "Error!"))) == `assertNotThrown failed: StringException was thrown: Error!`);
Asserts that the given expression
throws the given type of Throwable
. The Throwable
is caught and does not escape assertThrown
. However, any other Throwable
s will escape, and if no Throwable
of the given type is thrown, then an AssertError
is thrown.
T | The Throwable to test for. |
E expression
| The expression to test. |
string msg
| Optional message to output on test failure. |
string file
| The file where the error occurred. Defaults to __FILE__ . |
size_t line
| The line where the error occurred. Defaults to __LINE__ . |
AssertError
if the given Throwable
is not thrown.import core.exception : AssertError; import std.string; assertThrown!StringException(enforce!StringException(false, "Error!")); //Exception is the default. assertThrown(enforce!StringException(false, "Error!")); assert(collectExceptionMsg!AssertError(assertThrown!StringException( enforce!StringException(true, "Error!"))) == `assertThrown failed: No StringException was thrown.`);
Enforces that the given value
is true
.
T value
| The value to test. |
E | Exception type to throw if the value evalues to false . |
const(char)[] msg
| The error message to put in the exception if it is thrown. |
string file
| The source file of the caller. |
size_t line
| The line number of the caller. |
value
, if cast(bool) value
is true
. Otherwise, new Exception(msg)
is thrown. enforce
is used to throw exceptions and is therefore intended to aid in error handling. It is not intended for verifying the logic of your program. That is what assert
is for. Also, do not use enforce
inside of contracts (i.e. inside of in
and out
blocks and invariant
s), because they will be compiled out when compiling with -release. Use assert
in contracts. auto f = enforce(fopen("data.txt")); auto line = readln(f); enforce(line.length, "Expected a non-empty line.");
Enforces that the given value
is true
.
T value
| The value to test. |
Dg dg
| The delegate to be called if the value evaluates to false . |
file | The source file of the caller. |
line | The line number of the caller. |
value
, if cast(bool) value
is true
. Otherwise, the given delegate is called. The safety and purity of this function are inferred from Dg
's safety and purity.Enforces that the given value
is true
.
T value
| The value to test. |
Throwable ex
| The exception to throw if the value evaluates to false . |
value
, if cast(bool) value
is true
. Otherwise, ex
is thrown. auto f = enforce(fopen("data.txt")); auto line = readln(f); enforce(line.length, new IOException); // expect a non-empty line
Enforces that the given value
is true
, throwing an ErrnoException
if it is not.
T value
| The value to test. |
string msg
| The message to include in the ErrnoException if it is thrown. |
value
, if cast(bool) value
is true
. Otherwise, new ErrnoException(msg)
is thrown. It is assumed that the last operation set errno
to an error code corresponding with the failed condition. auto f = errnoEnforce(fopen("data.txt")); auto line = readln(f); enforce(line.length); // expect a non-empty line
If !value
is false
, value
is returned. Otherwise, new E(msg, file, line)
is thrown. Or if E
doesn't take a message and can be constructed with new E(file, line)
, then new E(file, line)
will be thrown.
This is legacy name, it is recommended to use enforce!E
instead.
auto f = enforceEx!FileMissingException(fopen("data.txt")); auto line = readln(f); enforceEx!DataCorruptionException(line.length);
Ditto
Catches and returns the exception thrown from the given expression
. If no exception is thrown, then null
is returned and result
is set to the result
of the expression
.
Note that while collectException
can be used to collect any Throwable
and not just Exception
s, it is generally ill-advised to catch anything that is neither an Exception
nor a type derived from Exception
. So, do not use collectException
to collect non-Exception
s unless you're sure that that's what you really want to do.
T | The type of exception to catch. |
E expression
| The expression which may throw an exception. |
E result
| The result of the expression if no exception is thrown. |
int b; int foo() { throw new Exception("blah"); } assert(collectException(foo(), b)); int[] a = new int[3]; import core.exception : RangeError; assert(collectException!RangeError(a[4], b));
Catches and returns the exception thrown from the given expression
. If no exception is thrown, then null
is returned. E
can be void
.
Note that while collectException
can be used to collect any Throwable
and not just Exception
s, it is generally ill-advised to catch anything that is neither an Exception
nor a type derived from Exception
. So, do not use collectException
to collect non-Exception
s unless you're sure that that's what you really want to do.
T | The type of exception to catch. |
E expression
| The expression which may throw an exception. |
Catches the exception thrown from the given expression
and returns the msg property of that exception. If no exception is thrown, then null
is returned. E
can be void
.
If an exception is thrown but it has an empty message, then emptyExceptionMsg
is returned.
Note that while collectExceptionMsg
can be used to collect any Throwable
and not just Exception
s, it is generally ill-advised to catch anything that is neither an Exception
nor a type derived from Exception
. So, do not use collectExceptionMsg
to collect non-Exception
s unless you're sure that that's what you really want to do.
T | The type of exception to catch. |
E expression
| The expression which may throw an exception. |
void throwFunc() { throw new Exception("My Message."); } writeln(collectExceptionMsg(throwFunc())); // "My Message." void nothrowFunc() {} assert(collectExceptionMsg(nothrowFunc()) is null); void throwEmptyFunc() { throw new Exception(""); } writeln(collectExceptionMsg(throwEmptyFunc())); // emptyExceptionMsg
Value that collectExceptionMsg returns when it catches an exception with an empty exception message.
Casts a mutable array
to an immutable array
in an idiomatic manner. Technically, assumeUnique
just inserts a cast, but its name documents assumptions on the part of the caller. assumeUnique(arr)
should only be called when there are no more active mutable aliases to elements of arr
. To strengthen this assumption, assumeUnique(arr)
also clears arr
before returning. Essentially assumeUnique(arr)
indicates commitment from the caller that there is no more mutable access to any of arr
's elements (transitively), and that all future accesses will be done through the immutable array
returned by assumeUnique
.
Typically, assumeUnique
is used to return arrays from functions that have allocated and built them.
T[] array
| The array to cast to immutable. |
array
. string letters() { char[] result = new char['z' - 'a' + 1]; foreach (i, ref e; result) { e = cast(char)('a' + i); } return assumeUnique(result); }The use in the example above is correct because
result
was private to letters
and is inaccessible in writing after the function returns. The following example shows an incorrect use of assumeUnique
. private char[] buffer; string letters(char first, char last) { if (first >= last) return null; // fine auto sneaky = buffer; sneaky.length = last - first + 1; foreach (i, ref e; sneaky) { e = cast(char)('a' + i); } return assumeUnique(sneaky); // BAD }The example above wreaks havoc on client code because it is modifying arrays that callers considered immutable. To obtain an immutable
array
from the writable array
buffer
, replace the last line with: return to!(string)(sneaky); // not that sneaky anymoreThe call will duplicate the
array
appropriately. Note that checking for uniqueness during compilation is possible in certain cases, especially when a function is marked as a pure function. The following example does not need to call assumeUnique
because the compiler can infer the uniqueness of the array
in the pure function: string letters() pure { char[] result = new char['z' - 'a' + 1]; foreach (i, ref e; result) { e = cast(char)('a' + i); } return result; }For more on infering uniqueness see the unique and lent keywords in the ArchJava language. The downside of using
assumeUnique
's convention-based usage is that at this time there is no formal checking of the correctness of the assumption; on the upside, the idiomatic use of assumeUnique
is simple and rare enough to be tolerable. Wraps a possibly-throwing expression in a nothrow
wrapper so that it can be called by a nothrow
function.
This wrapper function documents commitment on the part of the caller that the appropriate steps have been taken to avoid whatever conditions may trigger an exception during the evaluation of expr
. If it turns out that the expression does throw at runtime, the wrapper will throw an AssertError
.
(Note that Throwable
objects such as AssertError
that do not subclass Exception
may be thrown even from nothrow
functions, since they are considered to be serious runtime problems that cannot be recovered from.)
T expr
| The expression asserted not to throw. |
string msg
| The message to include in the AssertError if the assumption turns out to be false . |
string file
| The source file name of the caller. |
size_t line
| The line number of the caller. |
expr
, if any.import std.math : sqrt; // This function may throw. int squareRoot(int x) { if (x < 0) throw new Exception("Tried to take root of negative number"); return cast(int) sqrt(cast(double) x); } // This function never throws. int computeLength(int x, int y) nothrow { // Since x*x + y*y is always positive, we can safely assume squareRoot // won't throw, and use it to implement this nothrow function. If it // does throw (e.g., if x*x + y*y overflows a 32-bit value), then the // program will terminate. return assumeWontThrow(squareRoot(x*x + y*y)); } writeln(computeLength(3, 4)); // 5
Checks whether a given source
object contains pointers or references to a given target
object.
S source
| The source object |
T target
| The target object |
true
if source
's representation embeds a pointer that points to target
's representation or somewhere inside it. If source
is or contains a dynamic array, then, then these functions will check if there is overlap between the dynamic array and target
's representation. If source
is a class, then it will be handled as a pointer. If target
is a pointer, a dynamic array or a class, then these functions will only check if source
points to target
, not what target
references. If source
is or contains a union, then there may be either false
positives or false
negatives: doesPointTo
will return true
if it is absolutely certain source
points to target
. It may produce false
negatives, but never false
positives. This function should be prefered when trying to validate input data. mayPointTo
will return false
if it is absolutely certain source
does not point to target
. It may produce false
positives, but never false
negatives. This function should be prefered for defensively choosing a code path. doesPointTo(x, x)
checks whether x
has internal pointers. This should only be done as an assertive test, as the language is free to assume objects don't have internal pointers (TDPL 7.1.3.5).int i = 0; int* p = null; assert(!p.doesPointTo(i)); p = &i; assert( p.doesPointTo(i));
struct S { int v; int* p; } int i; auto s = S(0, &i); // structs and unions "own" their members // pointsTo will answer true if one of the members pointsTo. assert(!s.doesPointTo(s.v)); //s.v is just v member of s, so not pointed. assert( s.p.doesPointTo(i)); //i is pointed by s.p. assert( s .doesPointTo(i)); //which means i is pointed by s itself. // Unions will behave exactly the same. Points to will check each "member" // individually, even if they share the same memory
int i; int[] slice = [0, 1, 2, 3, 4]; int[5] arr = [0, 1, 2, 3, 4]; int*[] slicep = [&i]; int*[1] arrp = [&i]; // A slice points to all of its members: assert( slice.doesPointTo(slice[3])); assert(!slice[0 .. 2].doesPointTo(slice[3])); // Object 3 is outside of the // slice [0 .. 2] // Note that a slice will not take into account what its members point to. assert( slicep[0].doesPointTo(i)); assert(!slicep .doesPointTo(i)); // static arrays are objects that own their members, just like structs: assert(!arr.doesPointTo(arr[0])); // arr[0] is just a member of arr, so not // pointed. assert( arrp[0].doesPointTo(i)); // i is pointed by arrp[0]. assert( arrp .doesPointTo(i)); // which means i is pointed by arrp // itself. // Notice the difference between static and dynamic arrays: assert(!arr .doesPointTo(arr[0])); assert( arr[].doesPointTo(arr[0])); assert( arrp .doesPointTo(i)); assert(!arrp[].doesPointTo(i));
class C { this(int* p){this.p = p;} int* p; } int i; C a = new C(&i); C b = a; // Classes are a bit particular, as they are treated like simple pointers // to a class payload. assert( a.p.doesPointTo(i)); // a.p points to i. assert(!a .doesPointTo(i)); // Yet a itself does not point i. //To check the class payload itself, iterate on its members: () { import std.traits : Fields; foreach (index, _; Fields!C) if (doesPointTo(a.tupleof[index], i)) return; assert(0); }(); // To check if a class points a specific payload, a direct memmory check // can be done: auto aLoc = cast(ubyte[__traits(classInstanceSize, C)]*) a; assert(b.doesPointTo(*aLoc)); // b points to where a is pointing
Thrown if errors that set errno
occur.
Operating system error code.
Constructor which takes an error message. The current global core.stdc.errno.errno
value is used as error code.
Constructor which takes an error message and error code.
ML-style functional exception handling. Runs the supplied expression
and returns its result. If the expression
throws a Throwable
, runs the supplied error handler instead and return its result. The error handler's type must be the same as the expression
's type.
E | The type of Throwable s to catch. Defaults to Exception
|
T1 | The type of the expression . |
T2 | The return type of the error handler. |
T1 expression
| The expression to run and return its result. |
T2 errorHandler
| The handler to run if the expression throwed. |
expression
, if it does not throw. Otherwise, returns the result of errorHandler
. //Revert to a default value upon an error: assert("x".to!int().ifThrown(0) == 0);You can also chain multiple calls to
ifThrown
, each capturing errors from the entire preceding expression
. //Chaining multiple calls to ifThrown to attempt multiple things in a row: string s="true"; assert(s.to!int(). ifThrown(cast(int) s.to!double()). ifThrown(cast(int) s.to!bool()) == 1); //Respond differently to different types of errors assert(enforce("x".to!int() < 1).to!string() .ifThrown!ConvException("not a number") .ifThrown!Exception("number too small") == "not a number");The
expression
and the errorHandler
must have a common type they can both be implicitly casted to, and that type will be the type of the compound expression
. //null and new Object have a common type(Object). static assert(is(typeof(null.ifThrown(new Object())) == Object)); static assert(is(typeof((new Object()).ifThrown(null)) == Object)); //1 and new Object do not have a common type. static assert(!__traits(compiles, 1.ifThrown(new Object()))); static assert(!__traits(compiles, (new Object()).ifThrown(1)));If you need to use the actual thrown exception, you can use a delegate.
//Use a lambda to get the thrown object. assert("%s".format().ifThrown!Exception(e => e.classinfo.name) == "std.format.FormatException");
This enum
is used to select the primitives of the range to handle by the handle
range wrapper. The values of the enum
can be OR
'd to select multiple primitives to be handled.
RangePrimitive.access
is a shortcut for the access primitives; front
, back
and opIndex
.
RangePrimitive.pop
is a shortcut for the mutating primitives; popFront
and popBack
.
Handle exceptions thrown from range primitives.
Use the RangePrimitive
enum to specify which primitives to handle. Multiple range primitives can be handled at once by using the OR
operator or the pseudo-primitives RangePrimitive.access
and RangePrimitive.pop
. All handled primitives must have return types or values compatible with the user-supplied handler.
E | The type of Throwable to handle. |
primitivesToHandle | Set of range primitives to handle. |
handler | The callable that is called when a handled primitive throws a Throwable of type E . The handler must accept arguments of the form E, ref IRange and its return value is used as the primitive's return value whenever E is thrown. For opIndex , the handler can optionally recieve a third argument; the index that caused the exception. |
Range input
| The range to handle. |
struct
that preserves the range interface of input
. std.range.Take
when sliced with a specific lower and upper bound (see std.range.primitives.hasSlicing
); handle
deals with this by take
ing 0 from the return value of the handler function and returning that when an exception is caught.import std.algorithm.comparison : equal; import std.algorithm.iteration : map, splitter; import std.conv : to, ConvException; auto s = "12,1337z32,54,2,7,9,1z,6,8"; // The next line composition will throw when iterated // as some elements of the input do not convert to integer auto r = s.splitter(',').map!(a => to!int(a)); // Substitute 0 for cases of ConvException auto h = r.handle!(ConvException, RangePrimitive.front, (e, r) => 0); assert(h.equal([12, 0, 54, 2, 7, 9, 0, 6, 8]));
import std.algorithm.comparison : equal; import std.range : retro; import std.utf : UTFException; auto str = "hello\xFFworld"; // 0xFF is an invalid UTF-8 code unit auto handled = str.handle!(UTFException, RangePrimitive.access, (e, r) => ' '); // Replace invalid code points with spaces assert(handled.equal("hello world")); // `front` is handled, assert(handled.retro.equal("dlrow olleh")); // as well as `back`
Convenience mixin for trivially sub-classing exceptions
Even trivially sub-classing an exception involves writing boilerplate code for the constructor to: 1) correctly pass in the source file and line number the exception was thrown from; 2) be usable with enforce
which expects exception constructors to take arguments in a fixed order. This mixin provides that boilerplate code.
Note however that you need to mark the mixin line with at least a minimal (i.e. just ///) DDoc comment if you want the mixed-in constructors to be documented in the newly created Exception subclass.
Current limitation: Due to bug #11500, currently the constructors specified in this mixin cannot be overloaded with any other custom constructors. Thus this mixin can currently only be used when no such custom constructors need to be explicitly specified.
class MeaCulpa: Exception { /// mixin basicExceptionCtors; } try throw new MeaCulpa("test"); catch (MeaCulpa e) { writeln(e.msg); // "test" writeln(e.file); // __FILE__ writeln(e.line); // __LINE__ - 5 }
string msg
| The message for the exception. |
string file
| The file where the exception occurred. |
size_t line
| The line number where the exception occurred. |
Throwable next
| The previous exception in the chain of exceptions, if any. |
string msg
| The message for the exception. |
Throwable next
| The previous exception in the chain of exceptions. |
string file
| The file where the exception occurred. |
size_t line
| The line number where the exception occurred. |
© 1999–2017 The D Language Foundation
Licensed under the Boost License 1.0.
https://dlang.org/phobos/std_exception.html