|
Describes the use of low-level programming macros to issue coding errors, runtime errors, warnings and status messages.
If you are already familiar with the TF library diagnostic facilities, here is a quick guide to picking the correct facility:
The intended use of the diagnostic facilities in the Tf Library is for documenting and communicating various abnormal conditions that can occur in your code. The facilities in the Tf Library, while effective, are fairly low-level. If your application or library has access to higher-level and more structured diagnostic facilities, you are urged to make use of them; if not, you should use the facilities in the Tf Library. Although these facilities are fairly simple, they are also highly configurable.
The diagnostic facilities in the Tf Library are appropriate for the following tasks:
To communicate errors, warnings, and status messages, the Tf Library first attempts to call a delegate which may be installed by a higher-level library. If there is no delegate installed, default actions include printing errors and warnings to stderr
, printing status messages to stdout
, printing stack traces, and terminating the program on fatal errors. The following list describes usage scenarios for the diagnostic facilities in the Tf Library:
Sometimes there is no reasonable way to proceed past a coding bug. In this case, use TF_FATAL_ERROR(). Again, be sure to give a clear and concise explanation of what went wrong. Following is an actual example from the Tf Library:
In this example, clients cannot dereference a NULL weak pointer.
Sometimes it is useful to let the condition itself be the error message. If you reasonably believe that no code-path could allow your condition to fail, then for brevity you might prefer TF_AXIOM(). This implies that use of TF_AXIOM() is designed to document internal assumptions of the code; if a client of your code passes illegal parameters to a public function, it is not appropriate to use TF_AXIOM() to catch this.
You can also use TF_AXIOM() for regression tests.
Here are some reasonable uses of TF_AXIOM():
You should avoid using TF_AXIOM() when it can fail because of a client's use of the code. (Killing off the program is serious enough; doing so without giving the client a strong indication of what they did wrong, and how to fix it, is extremely unhelpful.) The following code sample illustrates improper use of TF_AXIOM():
The above axiom fails when you try to use the "->" operator on a reference-counted pointer which points to NULL. Since a client can cause this to happen, you should use TF_FATAL_ERROR instead, as shown in this sample:
The following code sample demonstrates another improper use of TF_AXIOM(). The axiom is not good, because not
_instance
doesn't help anyone fix their code:
Instead, you should use TF_FATAL_ERROR as follows:
To report non-fatal errors, use the TF_ERROR system. That system is documented here: The TfError Error Posting System. Generally, errors reported this way will let execution continue. The system may turn the errors into Python exceptions when returning into Python. Also, if there are unhandled errors remaining at the end of an application iteration, the system may roll back the undo stack to the last known good state.
There are two convenience macros provided here that generate errors. Use TF_CODING_ERROR() to indicate a recoverable coding error. Use TF_RUNTIME_ERROR() to indicate a generic runtime error. Use TF_ERROR() to provide more specific error codes when possible.
Be sure to make the description of the bug clear (but concise), as in the following example:
In this case, leaving the parent as set originally is deemed acceptable, so the coding bug is non-fatal.
For situations where it is important to inform the user of an undesirable situation that you can handle, but which may lead to errors, use TF_WARN(). This will generally be displayed in the application, indicating the warning to the user.
For situations where it is important to inform the user of some expected status information, use TF_STATUS(). This will generally be displayed in the application (in a status bar, for instance).
If you need to get the name of the function you are currently in, use the TF_FUNC_NAME() macro. This macro returns the function's name as a string. The name is meant for diagnostic purposes only, and while it should be human readable, no guarantees are made to the exact formatting of the string. Note that this macro is only callable from C++. If you need to get the function name from C, consider using the ARCH_FUNCTION or ARCH_PRETTY_FUNCTION macros.
For example:
The preceding code sample should display something like: "Debugging info about function YourClass::SomeMethod."