Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delphi - What is the "correct" order for except and finally blocks?

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?

like image 341
rossmcm Avatar asked Mar 04 '15 19:03

rossmcm


1 Answers

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.

like image 194
David Heffernan Avatar answered Oct 29 '22 04:10

David Heffernan