C+
Systems · v0.0.13

Function pointers

Function pointers exist; closures do not. There is no captured environment to reason about.

Type position

fn(i32, i32) -> i32          // takes two i32, returns i32
fn(*u8)                       // takes *u8, returns unit

Coercion

A bare function identifier coerces to a function pointer in a position that expects one:

extern fn atexit(cb: fn()) -> i32;
fn cleanup() { println(99); }

fn main() -> i32 {
    unsafe { atexit(cleanup); }    // bare name coerces
    return 0;
}

A struct of callbacks

struct Actions {
    on_click: fn(i32) -> i32,
    on_hover: fn(i32) -> i32,
}

let a: Actions = Actions { on_click: handle_click, on_hover: handle_hover };
let r: i32 = a.on_click(7);     // indirect call through the field

Stateful callbacks: the C convention

Function pointers do not capture environment, so for a callback that needs state, do what C does: pass (fn_ptr, user_data: *u8) and have the library thread user_data back to you unchanged.

extern fn libfoo_subscribe(cb: fn(*u8, i32), user_data: *u8);

This is also how appkit wires UI callbacks: a named function plus an associated object, never a closure.