I had a discussion the other day: https://stackoverflow.com/a/42156860/937125
where I didn't quite understand why an Abort
was better than calling Exit
in that situation. I tend not to use it in my code flow. I consider it a bad practice and bad for code flow.
but @David's statement in the comments made me wonder if maybe I was missing something:
Without a silent exception, how would you abort an operation when deep down the call stack. For instance how would you abort a file copy operation with a 10 deep call stack? Isn't that exactly what exceptions are designed for? Sure you can code it without exceptions but it is much more verbose and error prone.
I can't imagine such situation. Can someone give me an example of such code/scenario, and convince me that Abort
in the above case is really a good thing and "much more verbose and error prone". (3-4 deep call stack is enough to illustrate)
Assume your program is doing a lengthy operation either in a separate thread or (even though it's frowned upon) calling Application.ProcessMessages. Now, you want the user to be able to abort that operation in a safe manner (that is: All resources are cleaned up, the data is in a consistent state etc.). So, the UI sets a flag somewhere and in your code you periodically check for that flag. If it is set, you call Abort or explicitly raise EAbort. This will cause all your carefully crafted try / except / finally blocks to be execute and making sure aborting the operation is safe.
Of course this could be done with a different exception, but I can't think of any other way to safely exit from a deep call stack without having to program lots of ifs and exits.
The simplest scenario that illustrates my point is like so:
That's fine as it is. Now suppose that
MethodB
asks the user for some input, and if the user presses the Cancel button, that no further work should be carried out. You could implement that like this:That works fine, but imagine that you in the real world code, there was deeper nesting. The boolean returned by
MethodB
might need to be passed on up a great many levels. This would become cumbersome.Or consider what happens if
MethodB
needs to return a value to its caller. In that scenario the original code might be like so:Now once more consider what happens if the user gets a chance to cancel. How can we return both a boolean and a string from
MethodB
? Using an out parameter for one of the return values? Using a compound structure like a record to wrap both values. The latter obviously involves lots of boilerplate so let us explore the former.For sure you can do this, but this is beginning to look like the sort of code that exceptions were designed to simplify. And at this point, let us consider the existence of a silent exception,
EAbort
, raised by callingAbort
, that does not result in a message being shown by the top level exception handler. That last point is what is meant by silent.Now the code becomes:
The advantage is that
MethodA
does not need to worry about cancellation. And if the call stack was deeper, none of the methods betweenMethodA
at the top, andMethodB
at the point of user input, would need to know anything about cancellation.A further benefit is that
MethodB
can retain its natural signature. It returns astring
. In case of failure, either from a more traditional exception, or from user cancellation, an exception is thrown.This very simple example isn't that much more compelling than the previous one that does not use
Abort
. But imagine what the code would look like ifMethodB
were 4 or 5 deep in the call stack?I am absolutely not saying that
Abort
should always be used in place ofexit
. My belief is that both have their place. WhereAbort
shines is when the user opts to cancel an operation and you don't want any more processing to take place in the current event handler. Furthermore, since the user expressly opted to cancel, no further UI needs to be presented to them. You don't need a message box telling the user that they cancelled, they already know that.