Search code examples
delphi-10.1-berlindelphi

Delphi Error handling : Raise vs Exit on try...except...end


Is it safe to call Exit on try except? Or should I call raise instead?

I tried both example below and at raise example, the trace went through Delphi's internal library code. While exit just exit the procedure and nothing more.

I read that it's better to preserve application stack or queue or something like that. Will calling exit will break that stack?

Example 1 (raise)

SDDatabase1.StartTransaction;
Try
  SDQuery1.ApplyUpdates;
  SDDatabase1.Commit;
  SDQuery1.CommitUpdates;
Except
  SDDatabase1.Rollback;
  SDQuery1.RollbackUpdates;
  raise;
End;
..............//other codes I don't want to execute

Example 2 (exit)

SDDatabase1.StartTransaction;
Try
  SDQuery1.ApplyUpdates;
  SDDatabase1.Commit;
  SDQuery1.CommitUpdates;
Except
  SDDatabase1.Rollback;
  SDQuery1.RollbackUpdates;
  MessageDlg('Save Failed because: '+E.Message, mtError, [mbOK], 0);
  exit;
end;
..............//other codes I don't want to execute

Solution

  • Both are safe in principle, but it's impossible to recommend one or other approaches. It depends on your design intentions. You have to decide which is appropriate given the intended usage of the code.

    If you handle the exception in this code, and leave the function with exit, then the execution returns to the calling function, and it has no inkling of whether or not the function succeeded or failed. This may be problematic.

    If you re-raise the exception, execution will move to the next suitable exception handler up the call stack, passing through any finally blocks along the way.

    So, behaviour will differ, and it's down to you to decide which you want.

    It is a common beginner's mistake to attempt to handle exceptions further down the call stack than is ideal. For example, suppose you want your code to be used in both a GUI app and a non-visual app. Your use of MessageDlg would not be appropriate in a non-visual app.

    In a GUI app it is common for most actions to be in response to user input, for instance a button press. Exceptions typically should result in the entire operation being aborted. In which case you should not attempt to handle exceptions at all. Let them pass to the application level exception handler.

    Finally, your code treats all exceptions in the same way. This is often ill-advised. For instance, an access violation should surely be treated differently from a database error.