Try statements#
Code Example
Runnable Example in Jac and JacLib
# Try Statements
with entry {
# Basic try-except
try {
x = 5 / 0;
} except Exception {
print("caught exception");
}
# Try-except with as binding
try {
x = 5 / 0;
} except Exception as e {
print(f"error: {e}");
}
# Multiple except clauses
try {
x = int("not a number");
} except ValueError as ve {
print(f"ValueError: {ve}");
} except TypeError as te {
print(f"TypeError: {te}");
} except Exception as e {
print(f"other: {e}");
}
# Try-except-else (else executes if no exception)
try {
result = 10 / 2;
} except ZeroDivisionError {
print("division by zero");
} else {
print(f"success: {result}");
}
# Try-except-finally (finally always executes)
try {
x = 5 / 1;
} except Exception {
print("error");
} finally {
print("cleanup");
}
# Try-except-else-finally
try {
data = [1, 2, 3];
print(data[1]);
} except IndexError as ie {
print(f"index error: {ie}");
} else {
print("access successful");
} finally {
print("done");
}
# Try-finally (without except)
try {
print("operation");
} finally {
print("always runs");
}
# Nested try statements
try {
try {
x = 5 / 0;
} except ValueError {
print("inner ValueError");
}
} except Exception as e {
print(f"outer caught: {e}");
}
}
Jac Grammar Snippet
Description
Try Statements
Try statements provide structured exception handling, allowing you to catch and handle errors gracefully instead of letting them crash your program.
Basic Try-Except
Lines 5-9 demonstrate fundamental exception handling. The try block (lines 5-6) contains code that might raise an exception. When division by zero occurs on line 6, execution jumps to the except block (lines 7-9). Line 8 prints a message instead of crashing.
Exception Binding with 'as'
Lines 12-16 show binding the exception to a variable. Line 14 uses as e
to bind the exception object to variable e
, making it accessible in the handler. Line 15 prints the exception details. The variable is only available within the except block's scope.
Multiple Except Clauses
Lines 19-27 demonstrate handling different exception types:
Line | Exception Type | Handles |
---|---|---|
21 | ValueError |
Invalid value conversions |
23 | TypeError |
Type-related errors |
25 | Exception |
Any other exception |
Line 20 attempts int("not a number")
, which raises ValueError
. The except clauses are checked in order:
- Line 21 catches ValueError
(matches) - executes line 22
- Lines 23-24 would catch TypeError
(skipped)
- Lines 25-26 would catch any other Exception
(skipped)
Only the first matching except clause executes.
Try-Except-Else
Lines 30-36 demonstrate the else
clause. The else block (lines 34-35) executes only if no exception occurred in the try block. Line 31 succeeds, so line 35 executes. The else clause is useful for:
- Code that should only run on success
- Distinguishing setup (try) from success handling (else)
- Keeping exception-prone code isolated in the try block
Try-Finally
Lines 39-45 demonstrate the finally
clause. The finally block (lines 43-44) always executes, whether an exception occurred or not. Line 44 runs after the try block completes successfully. Finally clauses are essential for:
- Cleanup operations (closing files, releasing resources)
- Ensuring critical code runs regardless of errors
- Logging or auditing that must happen
Complete Try-Except-Else-Finally
Lines 48-57 show all four clauses together:
graph TD
A[Try Block] --> B{Exception?}
B -->|Yes| C[Matching Except Block]
B -->|No| D[Else Block]
C --> E[Finally Block]
D --> E
E --> F[Continue Execution]
Execution order: 1. Try block (lines 48-50) - Attempt operation 2. If exception: matching except block (lines 51-52) 3. If no exception: else block (lines 53-54) 4. Always: finally block (lines 55-56)
In this example, line 50 accesses a valid list index (no exception), so line 54 in else executes, then line 56 in finally executes.
Try-Finally Without Except
Lines 60-64 show try-finally without exception handling. This pattern ensures cleanup code runs even if an exception propagates up. The finally block executes before the exception is re-raised.
Nested Try Statements
Lines 67-75 demonstrate nested exception handling. Line 69 raises ZeroDivisionError
. The inner except (line 70) only catches ValueError
, so it doesn't match. The exception propagates to the outer try, where line 73 catches it as Exception
.
Exception Handling Flow
Scenario | Try | Except | Else | Finally |
---|---|---|---|---|
No exception | Executes | Skipped | Executes | Executes |
Exception caught | Partial | Executes | Skipped | Executes |
Exception not caught | Partial | Skipped | Skipped | Executes (then re-raises) |
Exception Hierarchy
When using multiple except clauses:
- More specific exceptions should come first
- Exception
catches most exceptions, so it should be last
- Python checks except clauses sequentially
- First match wins
Example order:
1. ValueError
(specific)
2. TypeError
(specific)
3. Exception
(general)
Best Practices
The examples demonstrate several best practices: - Catch specific exceptions rather than broad catches - Use else for code that should only run on success - Use finally for cleanup that must always occur - Bind exceptions to variables when you need to examine them - Order except clauses from specific to general
Common Patterns
Try-except patterns for different scenarios: