IceOnlys Blog

All Around Microsoft Dynamics Business Central

The Hidden Cost of TryFunction in Business Central

While investigating the Business Central 26 CallStack performance improvements, I stumbled upon an interesting question: Does the TryFunction attribute add significant overhead when there are simpler alternatives?

The answer might surprise you.

The Test Setup

I created two simple functions to compare the performance of different error handling approaches:

Approach 1: Using TryFunction

local procedure GetNonExistingCustomerTryFunction()
begin
    if TryGetCustomer() then
        Message('Test!');
end;

[TryFunction]
local procedure TryGetCustomer()
var
    Customer: Record Customer;
begin
    Customer.Get('NONEXIST');
end;

Approach 2: Direct Return Value

local procedure GetNonExistingCustomerGet()
begin
    if GetCustomer() then
        Message('Test!');
end;

local procedure GetCustomer(): Boolean
var
    Customer: Record Customer;
begin
    exit(Customer.Get('NONEXIST'));
end;

The Results

After 500 executions of each approach, here are the measured times:

  • TryFunction approach: 743ms
  • Direct return value: 118ms

That's a 6.3x performance difference! 🚀

Why This Matters

The TryFunction attribute in AL is designed to suppress errors and return a boolean indicating success or failure. However, this error handling mechanism comes with significant overhead:

  1. Error handling infrastructure: The runtime must set up error catching
  2. Stack unwinding preparation: Even if no error occurs, the infrastructure is in place
  3. Additional context switching: More layers of abstraction

When you're dealing with operations that naturally return a boolean (like Record.Get()), using TryFunction adds unnecessary complexity and performance cost.

Best Practice Recommendations

✅ Use Direct Return Values When Available

If a function naturally returns a boolean result (like Get(), Find(), Insert(), etc.), use it directly:

if Customer.Get(CustomerNo) then
    // Handle success
else
    // Handle not found

⚠️ Use TryFunction Only When Necessary

Reserve TryFunction for situations where you need to catch actual errors:

[TryFunction]
local procedure TryComplexOperation()
begin
    // Code that might throw various errors
    // that you want to handle gracefully
end;

Performance Impact in Real Scenarios

Let's put this into perspective:

  • 500 calls difference: ~625ms
  • 1000 calls: ~1.25 seconds
  • 10000 calls: ~12.5 seconds

In batch operations or frequently called code paths, this overhead accumulates quickly. If you're processing thousands of records, the difference between 118ms and 743ms per 500 operations becomes very significant.

Connection to CallStack Performance

This discovery relates directly to my previous post about CallStack performance improvements. Both findings highlight how error handling mechanisms in Business Central can have substantial performance implications:

  • CallStack operations can be slow when checking error contexts
  • TryFunction adds overhead even when errors don't occur

The pattern is clear: error handling infrastructure has a cost, and we should be mindful of when we really need it.

Conclusion

While TryFunction is a valuable tool in AL for error handling, it's not free. Before wrapping every operation in a TryFunction:

  1. Check if the operation already returns a boolean
  2. Consider if you really need to catch errors vs. handling return values
  3. Measure the performance impact in your specific scenario

Sometimes, the simplest solution is also the fastest one.