After implementing the throw() command and introducing the Try(Expression) keyword, we are excited to unveil the next evolution in 4D’s error handling system: the introduction of Try-Catch code blocks!
Starting from 4D 20 R5, users can enhance their error-handling capabilities by leveraging the power of the new Try, Catch, and End try keywords.
To illustrate the practical application of these new keywords, let’s explore an example involving the creation of invoices with invoice lines. This example will highlight the immediate benefits of these new keywords:
Function createInvoice($customer : cs.customerEntity; $items : Collection; $invoiceRef : Text) : cs.invoiceEntity
var $newInvoice : cs.invoiceEntity
var $newInvoiceLine : cs.invoiceLineEntity
var $item : Object
ds.startTransaction()
Try
$newInvoice:=This.new()
$newInvoice.customer:=$customer
$newInvoice.invoiceRef:=$invoiceRef
For each ($item; $items)
$newInvoiceLine:=ds.invoiceLine.new()
$newInvoiceLine.item:=$item.item
$newInvoiceLine.amount:=$item.amount
$newInvoiceLine.invoice:=$newInvoice
$newInvoiceLine.save()
End for each
$newInvoice.save()
ds.validateTransaction()
Catch
ds.cancelTransaction()
$newInvoice:=Null
ds.logErrors({\
message: "Invoice creation failed";\
errors: Last errors;\
customer: $customer.ID;\
invoiceRef: $invoiceRef;\
items: $items\
})
End try
return $newInvoice
In the creation process of this example, the developer is not concerned with the exact location where an error occurs. He simply wants to record the error and ensure he hasn’t created invalid data.
The function receives the customer entity, item collection, and invoice reference as parameters.
A transaction starts at the beginning to protect data integrity during the creation process.
All creation code is protected in a Try code block.
If the invoice and invoice lines have been created without error, the transaction is validated at the end of the Try code block.
But if an error occurs, the Catch code block is executed wherever it may have occurred in the Try code block. In the Catch code block, the transaction is canceled, and the error is logged by a custom function.
Try-Catch code blocks in details
To protect the execution of a code block against the display of a 4D error dialog box, you can now surround it with the Try and End try keywords.
Error handling is not mandatory, but it’s better! So you can now insert a Catch keyword before the End try keyword and write the error handling code on several lines between the Catch and End try keywords. This practice is common in other languages and makes long methods/functions easier to read!
When no error is triggered during the execution of the Try code block, the code skips the Catch code block, if any, and continues after the End try keyword.
But when an error is triggered by any line of code in the Try code block :
- If installed, the current error handler is not called.
- The 4D error dialog box is not displayed.
- The error is added to the current error stack.
- Code execution immediately switches to the Catch code block. If the Catch keyword is missing, code execution skips immediately after the corresponding End try keyword.
Note that if no error handler is defined for the current execution context and an error is triggered during the execution of the Catch code block, the 4D error dialog box is displayed. But you can also use Try(Expression) or nested Try–Catch code blocks to avoid displaying the 4D error dialog box!
About the error stack
Before the first line of the Try code block is executed, the current error stack is cleared. This behavior is beneficial in most cases, as it is unnecessary to compare the error stack before and after execution to detect new errors.
Therefore, if you wish to insert a Try–Catch code block into a Catch code block and retrieve the entire error stack, don’t forget to store it in a collection beforehand, as in this example:
var $errors : Collection
Try
throw(123; "First error")
Catch
$errors.push(Last errors)
Try
throw(456; "Second error")
Catch
$errors.push(Last errors)
// $errors collection contains the two previous errors
End try
End try
Mixing with global error handling
Error handling using the ON ERR CALL command is still relevant today. It can be used effectively with the Try(Expression) and Try–Catch code blocks. Just keep in mind the priority of error handling:
- Try(Expression). This is the most accurate method because it allows you to check for errors on a single line.
- Try–Catch code blocks. This is the best way to proceed when you consider line-by-line error checking irrelevant.
- ON ERR CALL command with the default option ek local to detect unmanaged errors in upcoming code execution in the current process/worker.
- ON ERR CALL command with the ek global and ek errors from components options to detect errors wherever an error handling system has not been installed or coded.
Don’t forget that the main advantages of coding error handling with Try(Expression) or Try–Catch code blocks are:
- placing the error handling as close as possible to the code that generates errors
- use local variables in the error handling code
You now have all the cards in your hand to handle errors as you wish, making your code safer!
We strive to provide our users with the best possible experience, and we encourage you to share your thoughts and comments on the 4D forum. Your feedback helps us understand your needs and continually improve our products and services.
Happy coding!