Function pointers

Function pointers let you store and call functions dynamically.

Getting a function pointer

Use & to get a pointer to a function:

fn double(x:i64 -- result:i64) {
    2 *
}

fn main() {
    &double -> fn_ptr
    // fn_ptr now holds a reference to double
}

Calling function pointers

Use call to invoke a function pointer:

fn double(x:i64 -- result:i64) {
    2 *
}

fn main() {
    &double -> fn_ptr
    5 fn_ptr call print nl  // 10
}

Passing functions as arguments

fn apply(x:i64 f:ptr -- result:i64) {
    -> f -> x
    x f call
}

fn double(x:i64 -- result:i64) { 2 * }
fn square(x:i64 -- result:i64) { dup * }
fn increment(x:i64 -- result:i64) { 1 + }

fn main() {
    5 &double apply print nl  // 10
    5 &square apply print nl  // 25
    5 &increment apply print nl     // 6
}

Storing in arrays

fn addition(a:i64 b:i64 -- r:i64) {
    +
}

fn subtraction(a:i64 b:i64 -- r:i64) {
    -
}

fn multiplication(a:i64 b:i64 -- r:i64) {
    *
}

fn div_op(a:i64 b:i64 -- r:i64) {
    /
}

fn main() {
    4 make<ptr> -> ops
    ops 0 &addition set
    ops 1 &subtraction set
    ops 2 &multiplication set
    ops 3 &div_op set

    10 5 ops 0 nth call print nl  // 15 (add)
    10 5 ops 1 nth call print nl  // 5 (sub)
    10 5 ops 2 nth call print nl  // 50 (mul)
    10 5 ops 3 nth call print nl  // 2 (div)
}

Callbacks

Use function pointers for callbacks:

fn for_each(arr:ptr callback:ptr -- ) {
    -> callback -> arr
    0 arr len 1 for i {
        arr i nth callback call
    }
}

fn print_item(x:i64 -- ) {
    -> x  // bind parameter
    x print " " print
}

fn main() {
    [1 2 3 4 5] &print_item for_each
    nl  // 1 2 3 4 5
}

Higher-order functions

Map

fn map(arr:ptr f:ptr -- result:ptr) {
    -> f -> arr
    arr len make<i64> -> result
    0 arr len 1 for i {
        result i arr i nth f call set
    }
    result
}

fn double(x:i64 -- r:i64) { 2 * }

fn main() {
    [1 2 3 4 5] &double map -> doubled
    0 doubled len 1 for i {
        doubled i nth print " " print
    }
    nl  // 2 4 6 8 10
}

Filter

fn filter(arr:ptr pred:ptr -- result:ptr) {
    -> pred -> arr

    // Count matches
    0 -> count
    0 arr len 1 for i {
        arr i nth pred call if {
            count 1 + -> count
        }
    }

    // Create result
    count make<i64> -> result
    0 -> j
    0 arr len 1 for i {
        arr i nth pred call if {
            result j arr i nth set
            j 1 + -> j
        }
    }
    result
}

fn is_even(x:i64 -- result:i64) {
    -> x  // bind parameter
    x 2 % 0 ==
}

fn main() {
    [1 2 3 4 5 6 7 8 9 10] &is_even filter -> evens
    0 evens len 1 for i {
        evens i nth print " " print
    }
    nl  // 2 4 6 8 10
}

Reduce

fn reduce(arr:ptr initial:i64 f:ptr -- result:i64) {
    -> f -> result -> arr
    0 arr len 1 for i {
        result arr i nth f call -> result
    }
    result
}

fn addition(a:i64 b:i64 -- r:i64) {
    +
}

fn main() {
    [1 2 3 4 5] 0 &addition reduce print nl  // 15
}

Storing in structs

struct Handler {
    name:str
    func:ptr
}

fn greet(name:str -- ) {
    -> name  // bind parameter
    "Hello, " print name print nl
}

fn farewell(name:str -- ) {
    -> name  // bind parameter
    "Goodbye, " print name print nl
}

fn main() {
    Handler {
        name = "greeter"
        func = &greet
    } -> h1
    Handler {
        name = "fareweller"
        func = &farewell
    } -> h2

    "Alice" h1 @func call
    "Bob" h2 @func call
}

Function tables

Dispatch based on a selector:

fn handle_cmd(cmd:i64 -- ) {
    -> cmd  // bind parameter

    4 make<ptr> -> handlers
    handlers 0 &cmd_help set
    handlers 1 &cmd_list set
    handlers 2 &cmd_add set
    handlers 3 &cmd_quit set

    cmd 0 >= cmd 4 < and if {
        handlers cmd nth call
    } else {
        "Unknown command" print nl
    }
}

fn cmd_help() {
    "Help message" print nl
}

fn cmd_list() {
    "Listing items" print nl
}

fn cmd_add() {
    "Adding item" print nl
}

fn cmd_quit() {
    "Quitting" print nl
}

What's next?

Learn about Anonymous Functions for inline function definitions, or Memory Management for manual memory control.