← Back to AILP Home

Extern — FFI with C

Overview

extern blocks declare C functions callable from Nitpick. Extern functions do not return Result<T> — they return raw values.

Syntax

extern "libm" {
    func:sin = double(double:x);
    func:cos = double(double:x);
    func:sqrt = double(double:x);
}

Or flat (no library block):

extern func:custom_func = int32(int32:a, int32:b);

Rules

  1. Extern blocks must be at file scope — not inside functions
  2. extern "lib" { } blocks have a limit of ≤7 declarations
  3. Flat extern func: declarations have no per-file limit
  4. Use void for no-return (not NIL): func:exit = void(int32:code);
  5. Use const (not fixed) inside extern blocks

String ABI

Direction Nitpick Type C Type
Parameter string const char*
Return string NitpickString {char* data, int64_t length}

C shims for string-returning functions must return the NitpickString struct.

Float ABI

Nitpick's flt32 passes as double at the C ABI level. C shims must use double params:

// C side
double my_func(double x) {    // NOT float!
    return (float)x * 2.0f;
}

Pointer Types in Extern

The canonical pointer ABI table is in memory/pointers.md. Short version:

Nitpick type C-side shape Use
int32-> int32_t * scalar pointer
MyStruct-> struct MyStruct * pointer to a C-layout-compatible struct
?* / ?-> void * erased/opaque pointer
int64 intptr_t-sized handle stable choice for library contexts and callbacks

For ownership-bearing C APIs, prefer a small C shim that exposes opaque int64/?* handles to Nitpick. That keeps lifetime and destroy rules explicit instead of relying on the compiler to understand C-side aliases.

Nitpick function values are fat closures ({fn_ptr, env_ptr} internally), not raw C callback pointers. Model C callback pointers as int64 or ?* at the Nitpick boundary and call them from shim code.

Example

extern "libc" {
    func:printf = int32(string:fmt);
    func:malloc = wild ?*(int64:size);  // erased pointer / void*
}

func:main = int32() {
    drop printf("Hello from C!\n");
    exit 0;
};

func:failsafe = int32(tbb32:err) {
    exit 1;
};

Related