Functions
Functions are first-class in ScarScript — declare them, return multiple values, capture variables in closures, or recurse freely.
Declaration
Use the func keyword. Parameters require type annotations; the return type is optional (inferred from the return statement).
// Full annotation
func add(a: int, b: int) int {
return a + b
}
// Return type inferred
func add(a: int, b: int) {
return a + b
}
// No parameters, no return
func hello() {
print("hi")
}
add(2, 3) // 5
hello()
func f() -> int. Both styles are accepted — pick whichever reads better.Multiple Returns
Return a tuple of values and destructure them at the call site:
func divide(a: int, b: int) (int, bool) {
if b == 0 {
return 0, false
}
return a / b, true
}
val result, ok = divide(10, 2)
if ok {
print("Result: {result}")
}
With explicit types on the destructuring:
val q: int, ok: bool = divide(10, 0)
Functions as Values (Closures)
Assign an anonymous function to a variable. Closures capture variables from the surrounding scope:
val multiply = func(x: int, y: int) int {
return x * y
}
multiply(3, 4) // 12
// Capture example
mut count = 0
val increment = func() {
count = count + 1
}
increment()
increment()
print(count) // 2
Anonymous functions work anywhere an expression is expected:
val nums = [1, 2, 3, 4, 5]
mut total = 0
for n in nums {
val double = func(x: int) int { return x * 2 }
total = total + double(n)
}
Recursion
Functions can call themselves. The checker registers all functions in a first pass, so call order doesn't matter:
func fib(n: int) int {
if n < 2 { return n }
return fib(n - 1) + fib(n - 2)
}
func factorial(n: int) int {
if n <= 1 { return 1 }
return n * factorial(n - 1)
}
print(fib(10)) // 55
print(factorial(5)) // 120
Call functions defined later in the file — forward references are allowed:
func start() {
print(helper()) // works — helper is registered in phase 1
}
func helper() str {
return "done"
}
start()
Return Semantics
The checker enforces that every code path returns a value when a return type is declared:
Always returns
func f(x: int) int {
if x > 0 { return 1 }
return 0
}
Missing return (error)
func f(x: int) int {
if x > 0 { return 1 }
// error: missing return
}
Unreachable code (error)
func f() int {
return 1
print("never runs")
// error: unreachable code
}
Passing Functions
Since functions are values, you can pass them around:
func apply(f: func(int) int, x: int) int {
return f(x)
}
val square = func(n: int) int { return n * n }
apply(square, 5) // 25
print and log are builtins — you cannot declare functions with those names.