AutolangDocs

Closures

Closures (anonymous functions) allow you to create blocks of code that can be passed around as variables and capture values from their surrounding scope. In Autolang, closure syntax is highly flexible but follows specific mandatory rules.

Basic Syntax

Every closure in Autolang must define its parameters inside vertical bars ||. You can define explicit data types for the parameters, or let the compiler infer them. If a closure requires a multi-line body, you can combine it with the arrow -> syntax.

// 1. Closure with no parameters (empty || is mandatory) val sayHello = {|| println("Hello from Autolang!") } sayHello() // 2. Closure with parameters and an explicit type (Single expression) val square = {|x: Int| x * x } println(square(5)) // Prints: 25 // 3. Closure with a block body using -> val checkEven: Int -> Void = {|num| -> { if (num % 2 == 0) { println("Even") } else { println("Odd") } }} checkEven(10) // Prints: Even

⚠️ Mandatory Syntax Rule

In Autolang, the || parameter delimiter is strictly required when declaring a closure. If you forget the || (for example, just writing literal body), the compiler will throw a syntax error.

Using Closures with Built-in Methods

Closures are extremely useful when working with data structures like Arrays. You can pass a closure directly into methods like forEach to iterate and manipulate elements.

val numbers = <Int>[1, 2, 3, 4, 5] // Passing a closure directly as an argument to forEach numbers.forEach {|value| println("Processing: " + value) } // Or executing multiple lines of code inside a block body var sum = 0 numbers.forEach {|value| -> { sum = sum + value println("Current sum: " + sum) }}

Trailing Closure Syntax

When a closure is the last argument of a function call, you can move it outside the parentheses. This is called trailing closure syntax and makes the code more readable — especially with methods like forEach, filter, and sort.

fun calculate(a: Int, b: Int, op: (Int, Int) -> Int): Int = op(a, b) // Standard call: closure inside parentheses val r1 = calculate(4, 5, {|a, b| a + b}) println(r1) // 9 // Trailing closure: moved outside parentheses val r2 = calculate(4, 5) {|a, b| a * b} println(r2) // 20

Value Capturing

Closures capture variables from their enclosing scope by value at the time the closure is created, not by reference. This means changes to the original variable after closure creation do not affect the captured copy inside the closure.

var x = 500 // Closure captures the value of x (500) at creation time val snapshot = {|| x} // Changing x later does NOT affect the captured value x = 999 println(snapshot()) // 500 <-- captured value, not the new x println(x) // 999 <-- current value of x

⚠️ Note on Mutable Captures

Because primitives are captured by value, a closure can only read the value at the time of creation. If you need shared mutable state, wrap the value in a class (e.g., a Box<T> wrapper).