Suppose I have the following routine:
function ReadFile(f : TFilename) : Boolean;
var
fs : TFileStream;
begin
Result := False;
try
fs := TFileStream.Create(f, ...);
try
// read file ...
Result := True;
finally
FreeAndNil(fs);
end;
except
// handle exceptions ...
end;
end;
What are the implications of having the except
and finally
transposed? I have seen plenty of posts with them both ways around, but I haven't seen a clear explanation of which is appropriate in which cases (I still think it is curious that in the above construct, the finally
block executes after the except
block!).
I have also seen posts that suggest that mixing try..except
and try..finally
blocks is not a good idea. How can you avoid it in situations where a routine throws an exception as part of normal operation - such as in some of the Indy routines?
There is no single correct way to write this. The two variants do different things. You may prefer one version in one scenario, the other in a different scenario.
Version 1, finally inner-most
function ReadFile(f : TFilename) : Boolean;
var
fs : TFileStream;
begin
Result := False;
try
fs := TFileStream.Create(f, ...);
try
// read file ...
Result := True;
finally
FreeAndNil(fs);
end;
except
// handle exceptions ...
end;
end;
Version 2, finally outer-most
function ReadFile(f : TFilename) : Boolean;
var
fs : TFileStream;
begin
Result := False;
fs := TFileStream.Create(f, ...);
try
try
// read file ...
Result := True;
except
// handle exceptions ...
end;
finally
FreeAndNil(fs);
end;
end;
The big difference is how the code behaves if TFileStream.Create
raises an exception, a far from implausible eventuality. In version 1, the exception will be caught and handled inside ReadFile
. In version 2, the exception will be passed out of ReadFile
and on up the chain of exception handlers.
Asides
You state:
I still think it is curious that in the above construct, the finally block executes after the except block!
That is not true for the code in your question, version 1 above. Perhaps you don't yet fully understand how finally and blocks operate.
A common mistake that is often observed, is a desire to catch and handle exceptions as soon as possible. That's the wrong strategy. The whole point about an exception is that it is not meant to happen and you usually don't know what to do when it does happen. Your goal is to handle exceptions as late as possible. For the vast majority of code you should simply not handle exceptions. Let them float upwards to a point in the code that is able to deal with the error.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With