Defining functions
Simple example
Use the fn keyword to create a function. Use -> to specify its return type. Use return to return a value from a function. All the code paths must return a value of the specified return type.
fn add_two_i32s(a: i32, b: i32) -> i32:
return a + bIf a function does not return anything (i.e its return type is void), its return type can be omitted:
fn print_i32(x: i32):
println(x)Recursive and mutually recursive functions
In Boa, functions can be recursive and mutually recursive:
// A recursive function
fn factorial(i: u32) -> u32:
return 1 if i == 0 else i * factorial(i - 1)// Two mutually recursive functions
fn is_even(i: u32) -> bool:
return true if i == 0 else is_odd(i - 1)
fn is_odd(i: u32) -> bool:
return false if i == 0 else is_even(i - 1)Tail-call optimization (TCO)
Functions that can be optimized with TCO will be optimized to a simple loop. Here is an example of such a function:
fn factorial2(i: i32, accumulator: u32) -> u32:
return accumulator if i == 0 else factorial2(i - 1, i * accumulator)The "naive" translation in assembly language would be something similar to:
factorial2:
; assuming i is in rdi, accumulator is in rsi, and rax is used for the return value
cmp rdi, 0
jz zero ; if i == 0
; return factorial2(i - 1, i * accumulator)
dec rdi ; i--
mul rsi, rdi ; accumulator *= i
call factorial2 ; function call, slower than a jump
ret
zero:
; return accumulator
mov rax, rsi
retWhereas an optimized version using TCO would be:
factorial2:
; again, i is in rdi, accumulator is in rsi, and rax is used for the return value
cmp rdi, 0
jz zero ; if i == 0
; return factorial2(i - 1, i * accumulator)
dec rdi ; i--
mul rsi, rdi ; accumulator *= i
jmp factorial2 ; this is a "jmp" instead of a "call": it's basically a loop!
ret
zero:
; return accumulator
mov rax, rsi
retThe difference is the replacement of the call instruction by a jmp. Calls are slower because values are pushed onto the stack (such as the registers which must be saved to be restored later). Using a jmp removes the possibility of triggering a stack overflow.
First-class functions
In Boa, functions are said to be "first-class", meaning that they can be stored inside variables and passed around.
