User-defined functions (UDFs)
This page explains how to create and use user-defined functions (UDFs) in Simple Issue Language (SIL) programs to organize code into reusable components.
You can create and use user-defined functions in your SIL programs to encapsulate reusable logic. They help improve code organization, readability, and maintainability by breaking complex operations into smaller, manageable pieces.
Syntax and basic usage
A function is defined using the following syntax:
function <name>(<type> param1, <type> param2, ...) {
Instruction1;
...
InstructionN;
return <value>;
}
When creating a function, keep in mind the following key points:
The
<name>
of the function cannot contain spaces, and they cannot start with a numberParameters can be any valid SIL type.
The
return
statement is optional.
Example
This example function calculates issue priority based on severity and environment. It uses conditional logic to demonstrate parameter passing.
function calculatePriority(string severity, string environment) {
if (severity == "Critical" && environment == "Production") {
return "Highest";
} else if (severity == "Critical" && environment == "Development") {
return "High";
} else if (severity == "Major" && environment == "Production") {
return "High";
} else {
return "Medium";
}
}
// Usage examples:
string newPriority = calculatePriority("Critical", "Production"); // Returns "Highest"
Description:
The function calculatePriority("Critical", "Production")
receives "Critical"
and "Production"
as inputs and checks the first condition against an actual Jira issue. If the condition is met, it changes the priority of the Jira issue to Highest. If the condition is not met, the function continues by checking the next condition and so on.
This function can be reused throughout your SIL program whenever you need to calculate priority based on severity and environment. For example, when issues are created, when severity or environment fields are updated, as part of validation rules, or in bulk update operations.
Functions definition
SIL has strict rules about where function definitions can appear in your code.
Important:
All functions must be defined before any executable code.
You can declare global variables and constants before the function definitions.
The correct order must be:
Global variable declarations (with initialization if needed), including here any constant declarations
Function definitions
Executable code
This rule helps ensure that all functions are available when needed and prevents potential issues with code organization and variable scoping.
Invalid definition example
// This is INVALID:
number i; // Variable declaration
const number pi = 3.14; // Constant declaration
i = 0; // Error line, this is code execution - NOT ALLOWED HERE
function circleArea(number r) {
return r * r * pi;
}
The error occurs because you can't have executable code (like i = 0;
where i
is initialized to a constant) before function definitions.
Valid definition example
Running the above code in SIL Manager returns the following (in the Editor console):
Parameters definition
Here’s what you need to know about parameters definition in a function:
Parameters can be of any valid SIL type (string, number, boolean, etc.)
Parameters are passed by value; changes inside the function don't affect the original variables.
The parameter list can be of any length; it can be empty.
Examples
This example illustrates how different parameter types are defined and used in a function.
Running the example usage code in the SIL Manager returns the following result:
Pass-by-value behavior
Parameters in UDFs are passed by value in the following way:
A copy of the value is passed to the function.
Changes to the parameter inside the function don't affect the original variable.
The original variable keeps its value after the function exits.
Pass-by-value behavior is the same for all SIL basic types, arrays, and structs.
Example
This example demonstrates pass-by-value behavior for a UDF that takes a number parameter and adds 10 to it.
If run in the SIL Manager, the function returns the following result:
Example description:
First, the function gets a copy of the
testScore = 75
value to work with.Inside the function, it adds 10 to that copy, making it 85. The function prints this value: "Inside function, score is: 85"
After the function exits, both the original score (75) and the modified score (85) are printed.
Constant Parameters
Parameters of UDFs can be made read-only by using the const
keyword within the function.
Example
Default Parameters
Parameters can have defaults. This feature was introduced in SIL v5.8.0.0.
Note: Parameters with default values must appear after parameters without defaults.
The default value is used only when you don't provide a value for that parameter when calling the function. When you provide a value, it overrides the default.
Example
Variable visibility in UDFs
When writing UDFs, you can work with three different categories of variables:
Local variables that you create inside the function
Parameter variables that you pass into the function
Global variables that are available throughout your program
Understanding how and when you can use each category of variable helps you write more effective and maintainable code.
Variable category | Definition | Example |
---|---|---|
Local | These are variables you create inside your UDF. They:
| |
Parameter | These are variables that get passed into your UDF in the list of parameters. Important characteristics:
| |
Global | Variables that are already defined and can be used immediately (including in the UDF body); they are accessible throughout the entire program and you don’t have to declare them. These include:
| The |
Best practices for using variables in UDFs
Keep in mind that local variables have the most limited access (just within the
{
and}
of your UDF, while global variables have widest access.Minimize the use of global variables to reduce code complexity.
Use meaningful parameter names to improve code readability.
Document any global variables used within UDFs.
Consider passing needed values as parameters rather than relying on their global state.
Return value
When a UDF finishes running, it can send a value back to where it was called from. You can also use return
to stop the UDR from running further. This way, return values serve two purposes:
They provide a way to send results back to the code that called the UDF (like returning a calculation result.)
They allow you to exit the UDF at any point (for example, stop early if an error is found.)
Examples
This example returns a boolean result:
This example returns a calculated value:
Important notes about returns
Return types are dynamic.
SIL determines the return type at runtime, so there is no need to declare the return type in the UDF definition.
You cannot return two different types. This represents an error
Be careful with type compatibility when using the returned value. In the example below, the value of
myDate
will not be modified because there is an incompatibility betweennumber
(right-hand side, returned from the function) anddate
(left-hand side, the variable type).A UDF can return at most one value.
You can use
return;
without a value. UDFs always return a value, even ifreturn
is undefined. The result of empty returns is an undefined value.
Examples
These are examples of empty returns behavior:
Best practices for return values
Always consider what value your UDF should return.
Be consistent with return types within a single UDF.
Check for null/undefined values when using returned values.
Use meaningful return values that help explain the UDF's outcome.