Built-in errors, and user-defined errors behave distinctly differently:
Built-in error codes generate a useful error message when they reach the user. This helps with debugging
They are reduced to a warning message if they are handled by an error handler before reaching the user.
They can be fully muted by using SkipWarn.
User-defined error codes give only a generic, unhelpful error message
Since the values of the user User-defined error codes are given at runtime, there is no easy way (except symbol lookup) to determine what error has occurred.
A error message can be given to the user by using the ErrWrite instruction, but this will always write to the user and can not be muted with SkipWarn. To properly replicate the behavior of Built-in error codes, one would need to have a top-level error handler that wrote the ErrWrite, but this would also require a centralized datastore of all error codes in the system which hampers modularity.
Custom error messages can also be added as an XML file as part of a robware add-in (see picture below)
Long jumping helps to further complicate error handling.
The rapid programming language does not record the line number of errors generated like other languages.
When the program pointer propagates through at least one error handler, no records are being made of where the error originated and if the error ends up going to the user the program pointer will rest on the top-level procedure call that raised the error, not giving any indication where the error came from.
Once a module or features is properly tested and debugging is no longer a big concern, the features may be put into NoStepIn module. RaiseToUser can be used here to skip an error message to the user (but this suffers from many of the same issues as long jumping)
Having blanket error handling (unconditional RAISE) is often used in lieu of propper selective error handling, but in reality; it will only make the situation worse as it removes practically any signs of what has gone wrong in the case of an unexpected error.
Ideal ERROR Handling
The purpose of a well-built error handling system is:
1 - Enable program behaviors where a pre-built instruction is expected to fail as part of normal operation.
2 - Enable a pre-built instruction to give different error messages depending on the failure.
3 - Enable a program to respond to an unexpected error and minimize damage by properly shutting down.
4 - Communicate to the user what when wrong, how, and when, to aid in debugging.
5 - Be expandable and scalable
The RAPID ERROR Handler fails on points 4 and 5, but does work rather well for 1 through 3.
Better RAPID ERROR Handling
Enforcing/implementing the following should make our error handling in RAPID better:
Restrict the use of unconditional raising of all error codes in an error handler.
Restrict the use of RaiseToUser and Long Jumping.
Implement a top-level error handler that looks up the name of the error code before the hits the system error handler and stops execution. this does however require the main procedure to contain a blanket raise statement, contradicting the first rule.
Find a way to record the trace/stack to where the error occurred? is this even possible?
RAPID ERROR Handling
Standard Error handling has some weaknesses:
Built-in errors, and user-defined errors behave distinctly differently:
Built-in error codes generate a useful error message when they reach the user. This helps with debugging
They are reduced to a warning message if they are handled by an error handler before reaching the user.
They can be fully muted by using
SkipWarn
.User-defined error codes give only a generic, unhelpful error message
Since the values of the user User-defined error codes are given at runtime, there is no easy way (except symbol lookup) to determine what error has occurred.
A error message can be given to the user by using the
ErrWrite
instruction, but this will always write to the user and can not be muted withSkipWarn
. To properly replicate the behavior of Built-in error codes, one would need to have a top-level error handler that wrote theErrWrite
, but this would also require a centralized datastore of all error codes in the system which hampers modularity.Custom error messages can also be added as an XML file as part of a robware add-in (see picture below)
Long jumping helps to further complicate error handling.
The rapid programming language does not record the line number of errors generated like other languages.
When the program pointer propagates through at least one error handler, no records are being made of where the error originated and if the error ends up going to the user the program pointer will rest on the top-level procedure call that raised the error, not giving any indication where the error came from.
Once a module or features is properly tested and debugging is no longer a big concern, the features may be put into NoStepIn module.
RaiseToUser
can be used here to skip an error message to the user (but this suffers from many of the same issues as long jumping)Having blanket error handling (unconditional RAISE) is often used in lieu of propper selective error handling, but in reality; it will only make the situation worse as it removes practically any signs of what has gone wrong in the case of an unexpected error.
Ideal ERROR Handling
The purpose of a well-built error handling system is:
The RAPID ERROR Handler fails on points 4 and 5, but does work rather well for 1 through 3.
Better RAPID ERROR Handling
Enforcing/implementing the following should make our error handling in RAPID better:
RaiseToUser
and Long Jumping.