Exception Handling in Pascal
Object Pascal (as implemented in Free Pascal and Delphi) provides structured exception handling built around the Exception class and its descendants, replacing older error-code-checking patterns like IOResult with a mechanism where an error condition is raised as an object using raise, and can be caught by a matching except block anywhere up the call stack, even several procedure calls away from where it occurred. This lets error-handling code live in one clear place instead of being scattered as if checks after every risky operation.
Cricket analogy: Raising an exception is like a fielder immediately signaling for a review the moment something looks wrong, and the decision gets handled up the chain by the third umpire, rather than every player individually having to check the replay after every single ball.
try..except and Exception Classes
A try...except block runs risky code in the try section and catches errors in the except section, where on E: ESomeException do filters for a specific exception class (and its descendants), giving access to the raised exception object E, including its .Message property. Multiple on handlers can be chained to handle different exception types differently, and a bare except ... end without any on clause catches any exception at all, though catching everything indiscriminately is usually a sign the handler is too broad.
Cricket analogy: Chaining on ERunOut do then on ECaught do handlers is like an umpire having a distinct, pre-defined protocol for a run-out review versus a catch review, rather than one vague 'something happened' response for every appeal.
type
EInsufficientFunds = class(Exception);
procedure Withdraw(var Balance: Currency; Amount: Currency);
begin
if Amount > Balance then
raise EInsufficientFunds.Create('Not enough funds for withdrawal');
Balance := Balance - Amount;
end;
var
balance: Currency;
begin
balance := 100.00;
try
Withdraw(balance, 250.00);
except
on E: EInsufficientFunds do
Writeln('Withdrawal failed: ', E.Message);
on E: Exception do
Writeln('Unexpected error: ', E.Message);
end;
end.try..finally for Cleanup
While try...except catches and handles errors, try...finally guarantees that cleanup code in the finally section always runs — whether the try section completed normally, exited early, or raised an exception that propagates onward unhandled. The idiomatic pattern for any resource that must be released is Obj := TSomeClass.Create; try ... finally Obj.Free; end;, ensuring the object is freed even if an exception occurs partway through using it, and the two constructs are often combined by nesting a try...except inside a try...finally (or vice versa) when a resource needs both guaranteed cleanup and error recovery.
Cricket analogy: A try...finally block covering fielding is like a captain who always resets the field back to a standard position at the end of an over no matter what happened during it — a wicket, a six, a wide — cleanup always runs regardless of the over's outcome.
The pattern Obj := TSomeClass.Create; try ... finally Obj.Free; end; should be used for every heap-allocated object that needs guaranteed cleanup — note that Create is called before the try begins, since if Create itself fails there is no object to free, and putting Create inside the try would risk calling Free on an object that was never successfully constructed.
Custom Exceptions and Best Practices
Defining a custom exception is as simple as declaring a class descending from Exception (or a more specific existing exception class), such as EInsufficientFunds = class(Exception);, which inherits the Create(Msg: string) constructor and .Message property automatically. Good practice is to catch the most specific exception types you can meaningfully recover from, let unrelated exceptions propagate up rather than swallowing them silently, and never leave an empty except end block, which hides real bugs by discarding error information entirely.
Cricket analogy: Defining EInsufficientFunds as a specific exception class is like a scoring app having a distinct 'NoBallException' rather than lumping every irregular delivery under one vague 'BadBall' flag — specificity lets each situation be handled correctly.
An empty except end; block (or one that only does except on E: Exception do ; end;) silently discards the exception entirely — the program continues as if nothing went wrong while the actual cause of the failure is lost forever. At minimum, log E.Message and the exception class name before deciding to suppress an error, and never suppress exceptions you don't specifically expect and know how to recover from.
- Exceptions are raised with
raise SomeException.Create('message')and caught with try...except. - on E: ESpecificException do filters for a specific exception class and exposes E.Message.
- Multiple on handlers can be chained to react differently to different exception types.
- try...finally guarantees cleanup code always runs, whether or not an exception occurred.
- The Create-then-try-finally-Free pattern ensures objects are freed even when errors occur mid-use.
- Custom exceptions are declared by descending from Exception or a more specific existing class.
- Never leave an empty except block — always log or meaningfully handle the caught error.
Practice what you learned
1. Which block guarantees its code runs whether or not an exception was raised?
2. What does `on E: EInsufficientFunds do` do inside an except block?
3. In the pattern `Obj := TSomeClass.Create; try ... finally Obj.Free; end;`, why is Create called before try begins?
4. How is a custom exception class typically defined?
5. Why is an empty `except end;` block considered bad practice?
Was this page helpful?
You May Also Like
File Handling in Pascal
Master reading and writing text, typed, and untyped files in Pascal, along with safe error handling for I/O operations.
Object Pascal Basics
Get started with Object Pascal's classes, methods, constructors, and inheritance — the object-oriented extension of standard Pascal.
Dynamic Memory Management
Understand pointers, the heap, and how to allocate, use, and free dynamic memory safely in Pascal.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics