1. Block Expressions

9. Block Expressions

Block expressions allow grouping multiple statements together and returning a value from the final expression. They create a new scope for variable declarations and enable sequential execution with proper scoping rules.

block_expression := '{' statement* expression? '}'

Examples:

// Simple block with local variables
let result = {
    let x = 10
    let y = 20
    x + y
}
print("Result: ${result}")  // prints "Result: 30"

// Nested blocks
let complex = {
    let outer = 100
    let inner_result = {
        let inner = 50
        outer + inner
    }
    inner_result * 2
}
print("Complex: ${complex}")  // prints "Complex: 300"

// Block with function calls
fn multiply(a: int, b: int) -> int = a * b
let calc = {
    let a = 5
    let b = 6
    multiply(a: a, b: b)
}
print("Calculation: ${calc}")  // prints "Calculation: 30"

9.1 Block Scoping Rules #

Block expressions create a new lexical scope:

  • Variables declared inside a block are only visible within that block
  • Variables from outer scopes can be accessed (lexical scoping)
  • Variables declared in a block shadow outer variables with the same name
  • Variables go out of scope when the block ends

Scoping Examples:

let x = 100
let result = {
    let x = 50        // Shadows outer x
    let y = 25        // Only visible in this block
    x + y             // Uses inner x (50)
}
print("Result: ${result}")  // 75
print("Outer x: ${x}")      // 100 (unchanged)
// print("${y}")            // ERROR: y not in scope

9.2 Block Return Values #

Block expressions return the value of their final expression:

  • If the block ends with an expression, that value is returned
  • If the block has no final expression, it returns the unit type
  • The block’s type is determined by the type of the final expression

9.3 Performance Characteristics #

Block expressions are zero-cost abstractions:

  • Compile-time scoping: All variable scoping resolved at compile time
  • No runtime overhead: Blocks compile to sequential instructions
  • Stack allocation: Local variables allocated on the stack
  • Optimized away: Simple blocks with no local variables are optimized away