By default, an Error() call in AL stops execution completely. The transaction rolls back and the user lands back on the last stable page. That's usually what you want, but sometimes you need to attempt something that might fail, react to the failure, and keep going. That's what the [TryFunction] attribute is for.
Before
procedure ConvertToDecimal(Text: Text): Decimal
begin
exit(Text2Decimal(Text)); // throws if Text isn't a valid number, kills the whole run
end;After
[TryFunction]
procedure TryConvertToDecimal(Text: Text; var Result: Decimal)
begin
Result := Text2Decimal(Text);
end;if TryConvertToDecimal(InputText, ConvertedValue) then
ProcessValue(ConvertedValue)
else
Message('Could not convert "%1" to a number, skipping.', InputText);Marking a procedure with the [TryFunction] attribute implicitly changes its return type to Boolean. You can't declare your own return value, so any value you need back has to go through a var parameter instead. Call it, and it returns true on success or false if an error occurred inside it, letting the caller branch instead of the whole operation dying.
TryFunction are not automatically rolled back when it fails. Microsoft's own guidance is not to include write transactions inside a try function. Treat it as a tool for catching and reacting to errors, not for wrapping database writes you want undone on failure.It's a small pattern, but it's the difference between "the whole batch job dies on record 4,000" and "record 4,000 gets logged as a failure and the job keeps going."
