Sometimes things go wrong at runtime: a file is missing, a network connection drops, or you accidentally divide by zero. Exception handling allows you to catch these errors and react to them, instead of letting your script crash.
Use try...except to wrap code that might fail. If an error occurs, the except block is executed.
try
// Risky code
var zero := 0;
var x := 1 div zero;
except
on E: Exception do
PrintLn('An error occurred: ' + E.Message);
end; An error occurred: Division by zero *
You can catch specific types of exceptions using the on E: ExceptionType do syntax. The else clause can be used as a catch-all.
The finally block is guaranteed to execute whether an exception occurred or not. This is perfect for cleaning up resources like closing files or freeing objects.
If you use exit to leave a function early from within a try block, the finally block still runs before the function actually returns.
DWScript allows you to combine both into a single block. The except part handles errors, and the finally part handles cleanup.
var f : File;
try
f := FileOpen('data.txt', fmOpenRead);
// Read file...
if f.Size = 0 then
raise new Exception('File is empty');
except
on E: Exception do
PrintLn('Error: ' + E.Message);
finally
if f.IsValid then f.Close;
end; Error: Invalid file handle *
You can trigger exceptions manually using the raise keyword. You can create a generic exception or define your own custom exception classes by inheriting from Exception.
type EMyError = class(Exception);
try
raise new EMyError('Something custom happened');
except
on E: EMyError do
PrintLn(E.Message);
end; Something custom happened
Assertions are a way to check if a condition is true during development. If the condition is false, an EAssertionFailed exception is raised.
var x := -1;
try
Assert(x > 0, 'x must be positive');
except
on E: Exception do
PrintLn(E.Message);
end; Assertion failed * : x must be positive
Sometimes you want to log an error but still let it propagate up to a higher-level handler. Using raise without an argument inside an except block re-raises the current exception.
procedure Log(msg: String); begin PrintLn(msg); end;
try
try
raise new Exception('Original Error');
except
on E: Exception do begin
Log('Error: ' + E.Message);
raise; // Re-throw
end;
end;
except
on E: Exception do ; // Suppress for demo
end; Error: Original Error
When an exception is caught, you can inspect its StackTrace property to see exactly where the error occurred and the sequence of calls that led to it. This is invaluable for debugging complex scripts.
try
raise new Exception('Error');
except
on E: Exception do
if E.StackTrace <> '' then PrintLn('Stack trace available');
end; Stack trace available
The ExceptObject magic function gives you access to the exception object currently being handled. It returns an Exception instance that is automatically populated within an except or finally block.
This is particularly useful in finally blocks to check if an exception is currently active, or in except blocks when you aren't using the on E: Exception binding.
When the host application (the Delphi environment running the script) throws an error that isn't caught by the host, it is wrapped in an EDelphi exception object before being passed to your script.
EDelphi inherits from Exception and adds an ExceptionClass property, which contains the name of the original Delphi exception class (e.g., 'EExternalException' or 'EAccessViolation').
try
// Call to a native function that fails at runtime
var fmt := '%d';
var s := Format(fmt, ['not a number']);
except
on E: EDelphi do begin
PrintLn('Native error of type: ' + E.ExceptionClass);
end;
on E: Exception do begin
PrintLn('Exception: ' + E.Message);
end;
end; Native error of type: EScriptError