Conditional Structures
Introduction
The conditional structures in Lipi Script is if. They can be utilized for the following purposes:
- For their side effects, i.e., when they do not return a value but perform actions, such as reassigning values to variables or calling functions.
- To return a value or a tuple that can then be assigned to one (or more, in the case of tuples) variable.
Conditional structures, like while structures, can be embedded; you can use an if inside another structure.
Some Lipi Script built-in functions cannot be called from within the local blocks of conditional structures. These functions include: , barcolor(), fill(), hline(), indicator(), plot(), plotbar(), plotcandle(), plotchar(), plotshape(),.** This restriction does not imply that their functionality cannot be controlled by conditions evaluated by your script — only that it cannot be done by including them in conditional structures.
Note that while input*.() function calls are allowed in local blocks, their functionality remains the same as if they were in the script’s global scope.
The local blocks in conditional structures must be indented by four spaces or a tab.
if Structure
Using if for Its Side Effects
An if structure utilized for its side effects has the following syntax:
if <expression> <local_block> {else if <expression> <local_block>} [else <local_block>]Where:
- Parts enclosed in square brackets ([]) can appear zero or one time, and those enclosed in curly braces () can appear zero or more times.
<expression>must be of bool type or be auto-castable to that type, which is only possible for int or float values (see the Type System page).<local_block>consists of zero or more statements followed by a return value, which can be a tuple of values. It must be indented by four spaces or a tab.- There can be zero or more else if clauses.
- There can be zero or one else clause.
When the <expression> following the if evaluates to true, the first local block is executed, the if structure’s execution ends, and the value(s) evaluated at the end of the local block are returned.
When the <expression> following the if evaluates to false, the successive else if clauses are evaluated, if any exist. When the <expression> of one evaluates to true, its local block is executed, the if structure’s execution ends, and the value(s) evaluated at the end of the local block are returned.
When no <expression> has evaluated to true and an else clause exists, its local block is executed, the if structure’s execution ends, and the value(s) evaluated at the end of the local block are returned.
When no <expression> has evaluated to true and no else clause exists, na is returned.
Using if to Return a Value
An if structure utilized to return one or more values has the following syntax:
[<declaration_mode>] [<type>] <identifier> = if <expression> <local_block> {else if <expression> <local_block>} [else <local_block>]Where:
- Parts enclosed in square brackets ([]) can appear zero or one time, and those enclosed in curly braces () can appear zero or more times.
<declaration_mode>is the variable’s declaration mode.<type>is optional, as is the case in almost all Lipi Script variable declarations (see types).<identifier>is the variable’s name.<expression>can be a literal, a variable, an expression, or a function call.<local_block>consists of zero or more statements followed by a return value, which can be a tuple of values. It must be indented by four spaces or a tab.
The value assigned to the variable is the return value of the <local_block>, or na if no local block is executed.
This is an example showing how na is returned when no local block is executed. If close > open is false in this case, na is returned:
x = if close > open {
close
}Scripts can include if structures that contain nested if statements and other conditional structures. For example:
if condition1
if condition2
if condition3
expressionNesting these structures is generally not advisable due to performance concerns. Whenever feasible, it’s usually more efficient to create a single if statement using multiple logical operators instead of relying on several nested if blocks:
if condition1 and condition2 and condition3
expressionMatching Local Block Type Requirement
When using multiple local blocks within structures, the return types of all local blocks must be consistent. This requirement applies only when the structure is utilized to assign a value to a variable in a declaration, as a variable can only have a single type. If the branches of the statement return two incompatible types, the variable’s type cannot be accurately determined. However, if the structure is not assigned to a variable, its branches can return different values.
The following code compiles successfully because both close and open are of float type:
x = if close > open {
close
}
else {
open
}This code fails to compile because the first local block returns a float value, whereas the second local block returns a string. Since the result of the if statement is assigned to the x variable, the types must match:
// Compilation error!
x = if close > open {
close
}
else {
"open"
}switch Statement
Overview
A switch statement allows you to compare a single value against multiple possible cases and execute different code blocks depending on which case matches.
It works as a cleaner alternative to multiple if ... else if ... else statements, making the code more readable and organized.
Syntax
switch <expression> {
case <value1>: <statement(s)>
case <value2>: <statement(s)>
...
default: <statement(s)>
}Parameters
| Part | Description |
|---|---|
<expression> | The value or variable to compare against the case values. |
case | Defines a possible match for the expression. If it matches, the associated statements are executed. |
default (optional) | Defines code to run if none of the cases match the expression. Only one default is allowed. |
Execution Flow
- The expression after
switchis evaluated once. - Each
caseis checked in the order they are written. - The first
casethat matches executes its statements. - If no case matches and a
defaultis present, thedefaultcode runs. - Only one case or default executes — once a match is found, the rest are ignored.
Example
indicator("Test", overlay=false)
x = 0
y = 0
s = "World"
switch s {
case "Hello": y := 1
case "World": y := 2
default: y := 3
}
plot(y)Step-by-Step Execution
- The variable
shas the value"World". switchcomparesswith:"Hello"→ No match."World"→ Match found.
- Executes:
y := 2 - Skips remaining cases (default not executed).
- Final value of
yis2.
Key Details
- Single Evaluation: The expression after
switchis only evaluated once. - Exact Match: Case values are matched exactly (case-sensitive for strings).
- No Fallthrough: Unlike some languages (e.g., C), there is no automatic execution of subsequent cases after a match — only the matched case runs.
- Default Optional: If
defaultis omitted and no case matches, no code in the switch block runs.
Common Use Cases
- Choosing behavior based on a text label.
- Executing different logic for different numeric codes.
- Handling multiple categories without long
if...elsechains.
Equivalent if...else Form
The above example is equivalent to:
if s == "Hello" {
y := 1
} else if s == "World" {
y := 2
} else {
y := 3
}Best Practices
- Keep
casevalues unique to avoid confusion. - Use
defaultto handle unexpected values. - Use descriptive variable names for clarity.
- Group related cases together for readability.