Exception handling
This page explains Simple Issue Language (SIL™ ) exception handling mechanisms, showing how to create and throw custom errors and catch them using try-catch blocks with different patterns. It provides guidance on handling both SIL and Java exceptions, from basic usage to nested error handling, along with some best practices for implementing error management in your SIL scripts.
SIL provides a practical approach to error handling that balances ease of use with error management capabilities. While the language is designed to handle minor issues by returning empty values where appropriate, there are situations where proper exception handling is necessary to ensure your scripts work reliably.
The language also lets you catch system-generated errors and create custom error handling logic. This flexibility allows you to manage errors in a way that makes sense for your particular use case, whether that's displaying user-friendly messages, logging issues for later review, or implementing recovery procedures.
There are two types of exceptions in SIL:
Java Exceptions that come from the underlying Java system that runs the SIL code.
SIL objects which are custom errors that you can create and throw in your own code using the
throw
keyword. This page focuses on this type of exception handling.
Throwing SIL objects
Any SIL value can be thrown as exception. Values can be constants, variables, or expressions.
The general syntax for throwing an exception from SIL is:
throw <value>;
Examples
// Example 1: Throwing a variable containing an error code
number errorCode = 404;
throw errorCode; // Throws the numeric value 404
// Example 2: Throwing a literal number
throw 2; // Throws the number 2 directly
// Example 3: Throwing a value from an array
struct ErrorInfo {
string fieldName;
string message;
}
ErrorInfo[] array = {
{"username", "Username is required"},
{"email", "Invalid email format"},
{"password", "Password too short"}
};
throw array[0].fieldName; // Throws "username"
// Example 4: Throwing a constructed error message using a structure
struct UserData {
string email;
string field;
}
UserData structure;
structure.email = "invalid@email";
structure.field = "email";
throw ("Field value invalid: " + structure.field); // Throws "Field value invalid: email"
// Example 5: Throwing a simple string message
throw "Generic error!"; // Throws the literal string "Generic error!"
Try-catch block
The try
-catch
block is SIL's main mechanism for handling errors. It lets you:
Write code that might produce errors in a
try
blockHandle any errors that occur in one or more
catch
blocksContinue program execution gracefully instead of crashing
Syntax and components
The general syntax for a try
-catch
block is the following:
try { // try block component
<// Code that might cause an error
} catch <type> <variableName> { // typed catch block component
// Handle specific type of error
} catch { // general catch block component
// Code to handle any error
}
A try
-catch
block can have three possible parts:
Component | Required | Description | How it works |
---|---|---|---|
Try block |
|
|
|
Typed catch block |
|
| If you have nested
|
General catch block (catch-all) |
|
|
Common patterns
Basic example
This example illustrates how the try
-catch
mechanism works:
If you run the script in SIL Manager, the output can be:
Think of it like a play script:
Actor says "Starting...".
Actor sees "Error occurred" and immediately exits stage.
String error handler comes on stage and announces the error.
Number error handler never appears (not needed).
Play continues with next line, "Continues here".
Type matching and catch all examples
This example illustrates how these two catch
components work:
The first example uses catch number err
which:
Only catches errors of the
number
type.Gives you access to the thrown value through
err
.Lets you work with the actual error value (2).
The second example uses catch
which:
Catches any type of error.
Doesn't provide access to the thrown value.
More general but less specific handling.
Nested try-catch example
In this example, the processUserData
function handles user information (name, age, email) with three layers of error checking:
Here’s what happens if you test with user.age = -5;
:
The middle layer catches the invalid age.
It converts it to error code 400.
The outer layer sees error code 400 and logs "Validation failed".
As shown in the screenshot below, the function returns false.
Test result in SIL Manager Editor console
Think of it like checking your ID:
Inner layer: checks your ID details
Middle layer: verifies your age
Outer layer: makes final decision to let you in or not
Java exceptions
This example shows how to handle Java exceptions in SIL:
Output for this example might look like:
Here are some key points about this example:
runAs()
is a SIL function that interacts with Java code.When Java code throws an exception, it can only be caught by a catch-all block.
Use
lastExceptionClass()
andlastExceptionMessage()
to get error details.Typed catch blocks (like
catch string
) won't handle Java exceptions.
Best practices
While try
-catch
blocks are powerful, carefully consider how to use them. Not every operation needs error handling, but when you do need it, make sure to apply some best practices to your code.
To enhance error specificity:
Catch specific errors before general ones.
Use typed
catch
blocks when you need the error value.Use general
catch
blocks for unexpected errors.
To improve error handling:
Log error details for debugging.
Clean up resources in all error paths.
Provide meaningful error messages.
Don't catch errors you can't handle properly.
To streamline code organization:
Keep
try
blocks focused on specific operations.Don't use
try
-catch
for normal flow control.Consider extracting complex error handling into separate functions.