An ErrorInstance is an object representing an error, containing an error code, error message, whether the error is critical (should it stop the program executing), and a user-specified trace of where the error has come from.
An ErrorInstance(code, message, isCritical, trace)
interface is provided so that ErrorInstances can easily be created. The interface returns the created error.
Parameter declaration | Description | Default |
---|---|---|
integer, optional :: code |
The error code. | 1 |
character(len=*), optional :: message |
Default message for the error (which there is plenty of opportunity to override). | "" |
logical, optional :: isCritical |
Is the error critical (i.e., should it stop the program)? | .true. |
character(len=*), optional :: trace(:) |
Custom trace for the error | - |
For example:
type(ErrorInstance) :: error
error = ErrorInstance(100, "Error message.", .false.)
ErrorInstances contain a "trace" property, which is in essence an array of character strings, the idea behind which is to provide a useful utility to give the ability to store information about the error trace - where it was triggered and through what route it has passed before being triggered. The trace is automatically printed when ErrorHandler%trigger()
is called.
Many debugging options already exist that print out an error backtrace (stack trace), detailing the trace of the error in terms of file names and line numbers. Whilst this is useful to the developer, it is often useless to the end user. The trace property attempts to plug this gap by providing the ability to build a custom trace based on what will be most useful information for the end user.
Note: A trace message is limited to a length of 256 characters.
This procedure adds the specified message to the array of trace messages for ErrorInstance objects, whilst for Result objects, it adds the same trace messages to all of the errors contained in the Result object (as Result objects can contain an array of errors).
Parameter declaration | Description | Default |
---|---|---|
character(len=*) :: message |
Trace message to add. | - |
The error trace becomes most useful when errors are passed from procedure-to-procedure. In each procedure, a new "node" can be added to the error to describe what was happening when the error occured. This works well when used alongside the Result object. Using the error trace, passing errors from nested procedure calls is more useful than triggering errors directly from those procedures, as it gives the end user much more information about where the error happened.
This arbitrary example contains two functions that are used to calculate the area of a circle, from a diameter and from a radius. The former calls another function to calculate the radius from the diameter, and this function checks that the provided diameter is positive (see the ErrorCriteria docs). The latter calculates the area directly and performs the positive check itself. The trace is formulated so we can see where the error was triggered from an where is passes through:
program trace
use ErrorInstanceModule
use ErrorCriteriaModule
use ResultModule
implicit none
type(ErrorCriteria) :: EH
type(Result0D) :: a1, a2
call EH%init()
a1 = areaFromRadius(-1.0)
a2 = areaFromDiameter(-2.0)
call EH%trigger(errors=[.error. a1, .error. a2])
contains
function radius(diameter)
real :: diameter
type(Result0D) :: radius
radius = Result( &
data = diameter/2, &
error = EH%positive(diameter) & ! Make sure diameter is positive
)
call radius%addToTrace('Radius from diameter')
end function
function areaFromDiameter(diameter) result(area)
real :: diameter
type(Result0D) :: area
area = Result( &
data = 3.142*.real.radius(diameter)**2, &
error = .error.radius(diameter) & ! Pass the error from the radius() function
)
call area%addToTrace('Area from diameter')
end function
function areaFromRadius(radius) result(area)
real :: radius
type(Result0D) :: area
area = Result( &
data = 3.142*radius**2, &
error = EH%positive(radius) & ! Make sure the radius is positive
)
call area%addToTrace('Area from radius')
end function
end program
This results in:
$ Error: Value must be positive. Given value: -1.00000000.
$ Trace: Area from radius
$ Error: Value must be positive. Given value: -2.00000000.
$ Trace: Radius from diameter > Area from diameter
$ ERROR STOP 108
The error code can be retrieved from an ErrorInstance object by the getCode()
procedure, which returns an integer. Note: The properties of ErrorInstances aren't currently private, and thus can be accessed directly from outside of the module (e.g., ErrorInstance%code
, ErrorInstance%message
). This might change in the future.
An ErrorInstance can be tested to see whether it is an error or the default "no error", using the functions ErrorInstance%isError()
and ErrorInstance%notError()
. Both return a logical value. This is particularly useful when returning errors from procedures (such as error criteria) to see whether the procedure resulted in an error. Furthermore, the ErrorInstance%isCriticalError()
procedure checks if the error is critical or not.