Error Handling¶
The old way and its shortcomings¶
In the old QPix every plug-in method would return an error code. This way of error reporting surely permits checking for the success or failure of every plug-in call, but eventually it leaves the method editor littered with error variable declarations and checks.
Also, for simple calls that may indicate a failure by the value of their
result, such a plug-in API is unnatural. For example, it’s way more natural to read
$image:=GetAreaImage(areaRef)
instead of $error:=GetAreaImage(areaRef;$image)
.
In the first case the empty result clearly indicates that the area contains no image. There
are many plug-in calls that don’t really need error checking because they just can’t fail
in normal use.
Further, there are cases where a plug-in method failure should be reported to the user (for example when a requested resource does not exist), cases where a failure should be handled by the developer, and cases where errors are actually assertion failures (quite common during development).
Finally, it was reasonable for QPix, due to its dependence on QuickTime and Altura, to stick with the classic MacOS error codes that its underlying technologies were using. With all of them dead and gone, it’s clearly time for something better.
The new way and how it works¶
Modern software consists of many different modules/libraries, each using error codes from its own domain. For example, in Q2Pix errors may come from the plug-in itself, from the OS (POSIX, Cocoa, Windows OS, WIC, Direct2D), from the XMP Toolkit SDK (the library that provides XMP editing), from PDFium (the library used for PDF manipulation and rendering on Windows), from C++ (the language used to build the plug-in), or from some other domain.
Q2Pix plug-in methods do not return error codes. Instead, the plug-in keeps an error info object per
process, similar to how 4D uses the Error
global/process variable:
Property name | Type | Description |
---|---|---|
Domain |
String |
The domain of the error. For errors triggered by Q2Pix the domain will be "Q2Pix" .
Other possible values include (but are not limited to) "POSIX" , "Cocoa" (on macOS),
"WIC" , "D2D" , "Win32" (on Windows), and "Pdfium" . |
Code |
Longint |
The error code, interpreted in the specific domain. |
Description |
String |
The description of the error (optional). |
Reason |
String |
The reason why the error happened (optional). |
Method |
String |
The method where the error occurred (optional). |
The error information is cleared on entry of every plug-in method call, and set when the method returns with some failure. The code becomes more natural and easier to read, without sacrificing any functionality.
Retrieving the error information is done via dedicated methods:
Errors triggered by Q2Pix are in the "Q2Pix"
domain. The error codes are listed in the
constants section.
Consider the following typical (old) QPix code that opens an image file and iterates over its frames:
C_TEXT($imagePath) $imagePath:="path:to:my:image.jpg" C_LONGINT($importer;$error) $error:=QPx_NewImporterForFile ($importer;$imagePath) If ($error=qpx_noErr) C_LONGINT($frameCount) $error:=QPx_CountImporterFrames ($importer;$frameCount) If ($error=qpx_noErr) For ($idx;1;$frameCount) // ... // Collect some image frame data // ... End for End if $error:=QPx_FreeImporter ($importer) Else ALERT("Could not open file due to error #"+String($error)+".") End if
The same code using Q2Pix would be:
C_TEXT($imagePath) $imagePath:="/path/to/my/image.jpg" C_TEXT($imgDocRef) $imgDocRef:=ImgDoc_CreateFromFile($imagePath) If ($imgDocRef#"") C_LONGINT($frameCount;$idx) $frameCount:=ImgDoc_GetFrameCount ($imgDocRef) For ($idx;1;$frameCount) // ... // Collect some image frame data // ... End for ImgObj_Release ($imgDocRef) Else ALERT("Could not open file due to an error:\n\n"+ImgErr_GetDescription) End if
Some observations:
- No compiler declaration for the
$error
variable (C_LONGINT($error)
).- Cleaner code.
- The failure message displayed to the user is more meaningful than just an error code.
- Though the call to
ImgDoc_GetFrameCount
will not fail with a valid image document reference, a defensive programmer would add an assertion right after that line to catch the impossible error during development:ASSERT(ImgErr_GetCode=0;"The sky is falling!")