NogcError

Mixes in the definition of a subclass of Error as well as a convenience function (e.g. myError()) to throw the single thread-local instance of that class.

The creation of the single instance is @nogc because the object that is thrown is emplaced on a thread-local memory buffer (both the object and the buffer it contains are allocated lazily). And throwing is @nogc because the thrown object is the single thread-local instance. Each NogcError object can carry arbitrary number of data of arbitrary types, which are emplaced inside the single error object. The size of data storage is specified with the maxDataSize template parameter.

The following examples use the NogcError!"foo" type and its associated fooError() function, which can be defined similarly to the following code:

// Define NogcError_!"foo", which will be thrown by calling fooError():
mixin NogcError!"foo";
mixin template NogcError (
string tag
size_t maxDataSize = 1024
) {}

Parameters

tag

a differentiating type _tag to allow multiple NogcError types with their associated single instances

maxDataSize

the size of the buffer to hold additional data accompanying the thrown error object

Bugs

The error data that is emplaced inside the error object are never destroyed. This decision is supported by the realization that the program is about to end due to the thrown NogcError.

Examples

/*
    Throwing from a pre-condition.

    In this case, the error is thrown while generating the string that the
    failed pre-condition is expecting. Such a string will never arrive at
    the pre-condition code.
*/
void test_1(int i)
in (i > 0, fooError("The value must be positive", i, 42))
{
    // ...
}
/*
    The .msg property of the error contains both the error string and the
    data that is included in the error.
*/
assertErrorStringContains(() => test_1(-1), [ "The value must be positive",
                                              "-1, 42" ]);

// Throwing from the body of a function
void test_2(int i)
{
    string otherData = "hello world";
    fooError("Something went wrong", otherData);
}
assertErrorStringContains(() => test_2(0), [ "Something went wrong",
                                             "hello world" ]);

// Throwing without any data
void test_3()
{
    fooError("Something is bad");
}
assertErrorStringContains(() => test_3(), [ "Something is bad" ]);

Meta