16

In Delphi, how can you use try, finally, and catch together? A Java/C# equivalent would look something like:

try {
    // Open DB connection, start transaction
} catch (Exception e) {
    // Roll back DB transaction
} finally {
    // Close DB connection, commit transaction
}

If you try this in Delphi, you can either use try/finally or try/except; but never all three together. I would like code like the following (which doesn't compile):

try
    // Open DB connection, start transaction
except on e: Exception do
begin
    // Roll back transaction
end
finally // Compiler error: expected "END" not "finally"
begin
    // Commit transaction
end
menjaraz
  • 7,551
  • 4
  • 41
  • 81
ashes999
  • 9,925
  • 16
  • 73
  • 124
  • Because `finally` and `except` are semantically totally different, in Delphi they cannot be in the same statement. Just look at the RTL/VCL sources where `finally` and `except` are used (and their ratio). You will hardly see places where they are near. – Jeroen Wiert Pluimers Nov 11 '10 at 16:29
  • 4
    Don't put "commit transaction" in a `finally` block. If an exception occurs, you don't want to commit anything. You especially don't want to try to commit a transaction that you already rolled back in the preceding `except` block. Commit should be the final action in the `try` section. – Rob Kennedy Nov 11 '10 at 20:58

3 Answers3

19

In Delphi you can use the following pattern:

// initialize / allocate resource (create objects etc.)
...
try
  try
    // use resource
    ...
  except
    // handle exception
    ...
  end;
finally
  // free resource / cleanup
  ...
end
mjn
  • 36,362
  • 28
  • 176
  • 378
  • 1
    Brilliant. I like how the nesting mimics the expected readability of try, catch, finally (as I'm used to from Java/C#). – ashes999 Nov 11 '10 at 15:29
  • 3
    Except it adds unnecessary level of indentation. I really wish they'd make it possible to write try..finally..except..end, even better if in random order (depending on what's processed first), and yet even better if it'd be possible to do "try..except A..finally..except B...end". It's really not that much in terms of coding, and does not burden the language, but adds a nice touch. – himself Nov 11 '10 at 16:08
  • @himself: how often have you seen an except and finally really close to each other? – Jeroen Wiert Pluimers Nov 11 '10 at 16:30
  • 2
    Quite a few times. A typical case is when you need to destroy some temporary objects AND handle exceptions. But due to ugliness of this pattern, people usually just duplicate the destruction code in "try" and "except" clauses. – himself Nov 11 '10 at 16:38
  • There's no use in `finally` in this case. – Eugene Mayevski 'Callback Apr 29 '12 at 06:01
  • @EugeneMayevski'EldoSCorp true, you simply have to fill in code instead of the final `...` to make sense – mjn Jan 18 '13 at 10:43
  • There's no *sense* to use finally in your case. Finally is used to execute the code if exception happens. In your code "free resource/cleanup" will be executed regardless of whether you write finally or not. Consequently, finally is redundant. – Eugene Mayevski 'Callback Jan 18 '13 at 10:49
  • @EugeneMayevski'EldoSCorp in case of unhandled exceptions, the finally will still be executed, how can this be redundant? – mjn Jan 18 '13 at 11:18
  • You handle all exceptions in except, don't you (at least this is what your comment there suggests)? And if you want to say that the code in except can throw another exception then, well, the code in Finally can do the same, so it's not an argument. – Eugene Mayevski 'Callback Jan 18 '13 at 13:30
  • @EugeneMayevski'EldoSCorp this should not be discussed here further (maybe it can be a new question on SO) – mjn Jan 18 '13 at 13:34
  • There's nothing to discuss, your code doesn't make much sense. – Eugene Mayevski 'Callback Jan 18 '13 at 15:03
10

write

try 
  // allocate resource here
  try 
  finally
    // free resource here
  end;
except
  // handle exception here
end;
Eugene Mayevski 'Callback
  • 45,135
  • 8
  • 71
  • 121
  • 2
    Equally functional as mjustin's answer, but I like his more -- it makes it more readable that the exception is caught first and then the finally block comes at the end. Or maybe I'm just biased since that's the Java/C# style :) – ashes999 Nov 11 '10 at 15:28
  • 5
    mjustin's answer doesn't catch exceptions in the destructor. This is better approach. – gabr Nov 11 '10 at 16:08
  • 3
    That hardly matters, @Gabr. If a destructor is throwing exceptions, you're already doomed. There is absolutely nothing your program can do to fix the problem that caused an error like that. – Rob Kennedy Nov 11 '10 at 18:01
  • Jim McKeeth has excellent video on Delayed Exception Handling (http://cc.embarcadero.com/item/26436) were he talks about problems in handling exceptions in the finally block. – Charles Faiga Nov 11 '10 at 23:07
  • 1
    RobK: If the destructor is freeing a resource, and the heap raises an exception, you're correct. If some user-written-method invoked inside Destroy notification in some object causes a non-fatal error that you want to catch, then that's where you're wrong. – Warren P Sep 20 '11 at 20:36
4

While nesting the try...except inside a try...finally (or vice versa) directly answers the question I would like to point out that original question, regardless of what language you are using, is mixing the concerns of error handling and resource management. Try...except and try...finally are ugly. They distract you from what your code is doing. A better approach is to extract error handling into a separate method:

procedure Read(Connection: TDBConnection);
begin
  try
    //Read DB
  except
    //Handle Exception
  end;
end;

procedure ReadRecord;
begin
  DBConnection.Open;
  Read(DBConnection);
  DBConnection.Close;
end;

Now your error handling is self-contained and can be ignored so you can concentrate your attention on the happy path.

Wait! What about the open and close? What if they raise exceptions?

Simple. Wrap those operations in try...except functions and handle them as well. It shouldn't be necessary. If the DB library your using is worth anything an exception in an open or close won't leave the connection in an unknown state. Then again, exceptions are there for the things you don't expect.

The same technique can be used with any resource: object creation, file access, etc. When the body of your function is guaranteed not to raise an exception try...finally is unnecessary.

There is, of course, function call overhead but in most cases it is negligible and your error handling functions should be small enough to let the compiler inline them.

Kenneth Cochran
  • 11,954
  • 3
  • 52
  • 117
  • +1 for going beyond the obvious question. Unfortunately, my question is pure syntactical, not semantical. – ashes999 Nov 18 '10 at 16:43