D has two features dedicated to error handling: exceptions and assertions. Exceptions are used to handle errors external to the program and assertions are used to verify assumptions inside the program. In other words, assertions are a debugging tool while exceptions handle situations that are beyond your control as a programmer.
Perform the following steps by using assertions and exceptions:
assert
.assert(0);
on any branch that you believe ought to be unreachable code.The code is as follows:
struct MyRange { int current = 0; @property bool empty() { return current < 10; } @property int front() { // it is a programming error to call front on an emptyrange // we assume current is valid, so we'll verify withassert. assert(!empty); return current; } void popFront() { // it is always a bug to call popFront on an emptyrange assert(!empty); current++; } } void appendToFile() { import core.stdc.stdio; auto file = fopen("file.txt", "at"); scope(exit) fclose(file); // Files if not opening is not a bug – it is an outsidecondition // so we will throw an exception instead of asserting. if(file is null) throw new Exception("Could not open file"); fprintf(file, "Hello! "); }
If you want to easily trigger the exception, try running this program in a read-only directory.
The key factor to consider when deciding whether you should use assert
or throw is: did this failure occur due to a program bug? Assertions are debugging tools. A correctly written program should never experience an assertion failure under any circumstances. Indeed, when compiled with the –release
switch to dmd
, assertions are removed from the generated code. Exceptions, on the other hand, do not indicate a bug in the program.
Generally, exceptions should be thrown only when a program fails to complete its operation. For example, a function that checks whether a file exists should not throw an exception if the file is not found. Instead, it should simply return false
. However, a function to copy or append to a file should throw an exception if the file is not found because it is impossible to copy a file that doesn't exist. The function could not do its job due to factors beyond the programmer's control, thus an exception is appropriate.
Any time you make an assumption about the state when programming, you should write it out explicitly with an assertion. Having too many asserts won't hurt you. They are removed from the release build so that there's no cost in your final build, and you can save a lot of debugging time if one of your assumptions proves to be invalid! For example, we demonstrated assert
with a range earlier. Suppose we didn't correctly check empty before calling front. This would result in our program reading corrupted data, a problem that might not be discovered until it ruins a file or causes some other bug in production.
That's the power of assert
; when used frequently, they help to find bugs as soon as the program's state becomes invalid. A failing assertion gives a location (file and line number in the source code), a stack trace, and optionally, a string message (the second argument to assert). An undetected bug gives a crash or corrupted result.
Exceptions are used for everything outside your control. If the condition can still fail even if you did a perfect job programming, use an exception instead of an assertion. Exceptions ought to use different types (child classes derived from Exception) to indicate different classes of problem. Phobos does not provide a generic exception hierarchy, instead opting to create Exception
subclasses as needed. You should also do this because handling exceptions with the catch statement differentiates them by dynamic type; using subclasses will let the consumer of your function choose which types of exception they can handle, while leaving the others unchanged.
It isn't wrong to throw an exception instead of using assert
. It is slightly less efficient and may surprise the user. When writing a library, some people opt to use exceptions instead of assertions even when it is a programmer bug, since the user code is beyond the control of the library author. This defensive programming is not wrong, but typically, D style encourages assertions, even in libraries. However, if you are in doubt, exceptions are always a safe choice.
3.138.123.106