Skip to content

Systems programming

Systems code sometimes needs pointers, platform APIs, or an existing C library. Zap keeps those operations explicit so the safe part of the program does not inherit their risk.

Use an unsafe block only where raw pointer work is required:

fun readFirst(values: *Int) Int {
unsafe {
return *values;
}
}

The caller still gets an ordinary Int. Put pointer validation, layout rules, and foreign data conversion close to this boundary.

Describe native linker flags once in thor.toml:

flags = "-L ./vendor/lib -l legacy"

Then declare the C ABI precisely in Zap:

ext fun legacy_start(mode: Int32) Int32;
fun main() Int {
unsafe {
return legacy_start(1) as Int;
}
}

Use @repr("C") for shared structs and @extern("C") for callbacks that C will call. Field order, field types, and function signatures must match the C declarations exactly.

Most application code should use safe Zap types, normal error handling, and the standard library. Reserve unsafe, raw pointers, and ABI declarations for the narrow integration layer.

Continue with Unsafe code and C interop for the full rules.