Conditional Statements
This chapter covers conditional control flow in Psy: if, else if, else, and match expressions.
If Statements
Basic If-Else
The most basic form of conditional control flow is the if expression:
fn min(a: Felt, b: Felt) -> Felt { if a < b { a } else { b } } fn main() { let x = 5; let y = 10; let result = min(x, y); // result is 5 }
If as Expression
In Psy, if is an expression that returns a value:
fn main() { let a = 10; let b = 11; let c = 12; let d = 13; // If expression assigned to variable let basic = if a > b { c } else { d }; // basic will be 13 since 10 > 11 is false }
If-Else If-Else Chains
You can chain multiple conditions using else if:
fn main() { let a = 10; let b = 11; let c = 12; let d = 13; let e = 14; let result = if a > b { c } else if b > a { d } else { e }; // result will be 13 since b > a (11 > 10) is true }
Nested If Statements
If statements can be nested within other if statements:
fn middle(a: Felt, b: Felt, c: Felt) -> Felt { if a > b { if b > c { b } else if a > c { c } else { a } } else { if a > c { a } else if b > c { c } else { b } } } fn main() { let result = middle(5, 3, 7); // Returns 5 let result2 = middle(1, 8, 4); // Returns 4 }
Complex Nested Examples
fn main() { let a = 10; let b = 11; let c = 12; let d = 13; let e = 14; // Nested if with multiple else if branches let embedded = if a > b { if a > b { c } else if b > a { d } else { e } } else if c > d { if a > b { c } else if b > a { d } else { e } } else { if a > b { c } else if b > a { d } else { e } }; }
If with Local Variables
You can declare variables inside if blocks:
fn main() { let a = 1; let b = 2; let c = 3; let d = 4; let result = if a > b { let tmp0 = 1; let tmp1 = 2; if tmp0 > tmp1 { tmp0 } else { tmp1 } } else if c > d { let tmp2 = 3; let tmp3 = 4; if tmp2 > tmp3 { tmp2 } else { tmp3 } } else { let tmp4 = 5; let tmp5 = 6; if tmp4 > tmp5 { tmp4 } else { tmp5 } }; }
If in Function Calls
If expressions can be used as arguments to function calls:
fn process(x: Felt, y: Felt) { // Function body } fn main() { let n1 = 1; let n2 = 2; process(if n1 > n2 { n1 } else { n2 }, n2); }
Match Expressions
Match expressions provide a powerful way to handle multiple possible values:
Basic Match
fn match_test_case(input: Felt) -> Felt { match input { 0 => 10, 1 => 20, 2 => 30, _ => 40, // Default case } } fn main() { let result1 = match_test_case(0); // Returns 10 let result2 = match_test_case(1); // Returns 20 let result3 = match_test_case(5); // Returns 40 (default case) }
Match with Blocks
Match arms can contain blocks for more complex logic:
#![allow(unused)] fn main() { fn match_with_blocks(input: Felt) -> Felt { let mut result = 0; match input { 0 => { result += 10; }, 1 => { result += 20; }, 2 => { result += 30; }, 3 => { result += 40; }, 4 => { result += 40; }, _ => { result += 50; }, }; result } }
Match as Expression
Match can be used as an expression to assign values:
fn main() { let input = 2; let base_value = match input { 0 => 100, 1 => 200, 2 => 300, _ => 400, }; // base_value will be 300 }
Match with Different Types
Match works with various types:
// Match with bool fn match_bool_test(input: bool) -> Felt { match input { true => 100, false => 200, } } // Match with u32 fn match_u32_test(input: u32) -> Felt { let mut result = 0; match input { 0u32 => { result += 5; }, 1u32 => { result += 15; }, 2u32 => { result += 25; }, 3u32 => { result += 35; }, 4u32 => { result += 45; }, _ => { result += 55; }, }; let extra = match input { 0u32 => 50, 1u32 => 150, 2u32 => 250, 3u32 => 350, _ => 450, }; result + extra } fn main() { let bool_result = match_bool_test(true); // Returns 100 let u32_result = match_u32_test(2u32); // Returns 275 (25 + 250) }
Complex Match Example
#![allow(unused)] fn main() { fn complex_match_example(input: Felt) -> Felt { let base = match input { 0 => { let temp = 10; temp * 2 }, 1 => { let temp = 20; temp + 5 }, 2 => { let temp = 30; temp - 5 }, _ => { let temp = 40; temp + 10 }, }; let multiplier = match input { 0 => 2, 1 => 2, 2 => 3, _ => 1, }; base * multiplier } }
Current Limitations
Multiple Patterns: Multiple patterns in match expressions (e.g., 0 | 1 => value) are not currently supported. Use separate match arms for each pattern:
#![allow(unused)] fn main() { // ❌ Not supported match value { 0 | 1 => result1, 2 | 3 => result2, _ => default, } // ✅ Use this instead match value { 0 => result1, 1 => result1, 2 => result2, 3 => result2, _ => default, } }
Important Notes
No Early Returns in Conditionals
Important: Psy does not support early returns within if statements:
#![allow(unused)] fn main() { fn example(x: Felt) -> Felt { // ❌ This will cause a compilation error // if x > 10 { // return x * 2; // } // ✅ Use expression-based returns instead if x > 10 { x * 2 } else { x } } }
Expression-Based Design
Both if and match are expressions in Psy, meaning they return values that can be assigned to variables or used in other expressions:
fn main() { let x = 5; // If as expression let result1 = if x > 0 { x } else { -x }; // Match as expression let result2 = match x { 0 => 0, n => n * 2, }; // Can be used in function calls process_value(if x > 0 { x } else { 0 }); } fn process_value(value: Felt) { // Function implementation }
Key Points
- If statements are expressions that return values
- Else if allows chaining multiple conditions
- Nested if statements are fully supported
- Match expressions provide pattern matching capabilities
- No early returns are allowed in conditional blocks
- All branches of an if expression must return the same type
- Default case in match expressions uses
_wildcard - Both if and match can be used anywhere expressions are expected