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 {
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.