I am still amazed to see how many (even seasoned) Delphi programmer don’t understand exceptions. This is a reply to the Silver Coder’s video.
He states that exceptions are not the best idea and the reason mentioned in the (way too) short video is that try/except makes the code slow and difficult to read.
I respectfully disagree with his statement, but for a totally reasons than the ones he listed. The correct reason is that you should never swallow exceptions.
His example was like this:
program Example;
var x,y: integer;
begin
x:= 10;
y:= 0;
try
x := x div y;
Writeln('x = ', x);
except
on e: exception do WriteLn( 'exception: bla bla bla');
end;
end;
My question would be what would you do if you have a routine that receives a zero as parameter? Replace zero with one? Don’t do the calculation? Show an error msg like “press yes to do the calculation anyway”? (What if you are in a console program? What if you don’t want to halt the program?)
Since his example is definitively unrealistic, let’s turn it into a more realistic piece of code:
program SplitCandies(CandyPieces, Kids: integer): integer;
begin
try
Result := CandyPieces div Kids;
except
Result:= ?; // ha ha ha, gotcha!
end;
end;
As we can see, letting a routine to continue (returning a fake result) after an exception IS NOT FINE! We don’t know how to recover if y = 0, therefore we cannot return a valid value.
What is the correct way to handle this? The Silver Coder suggests defensive programming – checking for zero inside the function. Let’s see this, again, in a more realistic scenario:
program SplitCandies(CandyPieces, Kids: integer): integer;
begin
if Kids > 0 // Defensive condition
then Result:= CandyPieces div Kids
else Result := ?; // Still gotcha!
end;
The above function is almost fine. So, let’s make it better. There! We fixed it:
program SplitCandies(CandyPieces, Kids: integer): integer;
begin
Result := CandyPieces div Kids;
end;
But you might say: But Gabriel, your function will crash if you have zero kids at the party. YES. Let the program crash and send a bug report (I hope you use madShi to generate bug reports). Get the bug report and and fix the code that is sending you a zero. There is where your problem resides!
program Party
begin
if PartyStarted
AND (KidCount > 0) <------ here was your problem
then SplitCandies(100, KidCount)
else ShowMessage('No kids at your birthday? You need some friends!');
end;
Problem fixed! No exception swallowing forced down on our throat.
Note: There are justified cases where you can use try/except but these are EXTREMELY rare. I have 700000 lines of personal code and I barely use it.
The justified cases are:
- When you know how to recover from the exception.
In most cases you don’t. - Driver, service and server apps that are not allowed to crash.
But this is not an excuse to swallow the exceptions. You should log the exceptions to a file.
But then you should have zero exceptions logged, and you should check that log at least once per day. Otherwise, it is not different than swallowing the exceptions. - You expect an error to occur.
For example when I process large number of images at batch, I ignore the Jpeg that are corrupted. But in this cases I trap ONLY the Jpeg-related errors, not all eceptions.
If anyone has a different example where try/except is fine, let us know (code example please).
If you are still unconvinced, I dedicated a full chapter in my book to exceptions.