Error management is often a constraining part of development in all languages. In 4D, if you forget to call an error-handling method in a new process/worker or use components that don’t handle errors, the built-in 4D error dialog can appear to the final user. 4D developers would like to catch all errors in all contexts to avoid displaying this built-in 4D error dialog.
Let’s see how we can manage this behavior with 4D v19 R8.
Global error handler
Until now, the best practice to handle errors in an execution context was to use the ON ERR CALL command and pass the method handler as a parameter. However, this error method was called only in the current process context.
From 4D v19 R8 on, you can also define a global error handler that will be efficient for all execution contexts. If you forgot to define a local error handler in a new process/worker, the global error handler would be invoked automatically. So, to save your application, you can define your global error handler in the On Startup database method, for example.
ON ERR CALL("myGlobalErrorHandler"; ek global)
Passing an error method to be called in the current process is still efficient. We renamed it a local error handler.
ON ERR CALL("myLocalErrorHandler")
// equivalent to:
ON ERR CALL("myLocalErrorHandler"; ek local)
Note that the local error handler is still invoked if defined, even if a global error handler is defined, so your defined local error handlers will run as usual. The global error handler is invoked only if no local error handler is defined in the current execution context.
ORDA functions and computed attributes on the 4D Server
As you may know, when an ORDA function or computed attribute is used on a client application, it is executed on the 4D Server side. So, if these functions or computed attributes don’t define a local error handler and throw errors, the built-in 4D error dialog is displayed on the 4D Server when not executed headless.
To avoid that, you can now define a global error handler on the server side in the On Server Startup database method per example:
ON ERR CALL("myServerGlobalErrorHandler"; ek global)
Components
As a component developer, it’s now easier for you to handle errors. You just have to define your global error handler in the On Host Database Event database method (e.g., in the On before host database startup event) to ensure that no error will display the built-in 4D error dialog in the host database! Doing this, all errors generated by the component will call the global error handler of the component without any side effects on the host database.
As a component user, you can make your application safer by handling component errors that haven’t been caught in the component execution context. Doing this, if you use components that don’t manage their own errors correctly, you can manage them, and no more built-in 4D error dialog will appear. To install a component error handler method, just use the corresponding parameter like this:
ON ERR CALL("myComponentErrorHandler"; ek errors from components)
This is also a global error handler but dedicated to errors uncaught by components so that you can develop specific stuff for these. Just note that the error system variables (error, error method, error line, and error formula) are not available in this component error handler because errors become from another execution context. But the error stack is still available.
COMMON BEHAVIORS
Error stack
We also introduced a new command to get the entire error stack: Last errors. This command returns a collection where each item is an error of the whole stack, each error containing information about the error number, the message, and the internal component signature.
Getting the current error handler
The Method called on the error command now admits an optional parameter to retrieve the global error handler and the component error handler, like in this sample:
$localHandler:=Method called on error
$globalHandler:=Method called on error(ek global)
$componentHandler:=Method called on error(ek errors from component)
Aborting error
No matter which handler is executed, the ABORT command is always practical and allows you to interrupt the code as usual.
You can test all these new behaviors with the HDI above.