Predictable memory
Zap’s memory management provides deterministic object lifetimes without stop-the-world pauses.
fun main() {
println("Hello, Zap!");
}@error
enum TinyError {
TooSmall,
}
fun ensureMin10(value: Int) Int!TinyError {
if value < 10 {
fail TinyError.TooSmall;
}
return value;
}
fun main() {
var ok: Int = ensureMin10(12) or 0; // success -> 12
var fb: Int = ensureMin10(3) or 99; // failure -> fallback 99
if ok != 12 { return 1; }
if fb != 99 { return 2; }
}class Box {
priv value: Int;
fun init(value: Int) {
self.value = value;
}
pub fun pick<T>(other: T) T {
return other;
}
pub fun current() Int {
return self.value;
}
}
fun main() {
var box: Box = new Box(7);
if box.current() != 7 {
return 1;
}
if box.pick<Int>(42) != 42 {
return 2;
}
if box.pick(true) != true {
return 3;
}
}Zap’s memory management provides deterministic object lifetimes without stop-the-world pauses.
Errors are explicit in the type system, so you can handle failures without exceptions or hidden runtime behavior.
Call C libraries through FFI and introduce Zap to an existing codebase one component at a time.
Zap is built for software that needs native performance and direct access to the hardware, without forcing every program to manage memory by hand.
Use the libraries you already rely on and adopt Zap gradually, without rewriting an entire codebase.
From small command line tools to low-level software, Zap gives you a clear path from idea to native code.
Zap keeps unsafe operations explicit, so the parts of your program that need extra control stay easy to find and review.
// In C, returning a pointer into a temporary packet would create a dangling
// pointer. Zap tracks which String owns every borrowed StringView instead.
fun receivePacket() String {
return "event:deploy";
}
fun payload(packet: StringView) StringView borrows(packet) {
return slice(packet, 6, packet.len - 6);
}
fun printPayload(value: noescape StringView) {
println("Payload: " + value);
}
fun main() Int {
// The returned view borrows from a temporary String. Zap keeps that hidden
// owner alive until the view's last use, so this cannot become use-after-free.
var temporaryPayload: StringView = payload(receivePacket());
printPayload(temporaryPayload);
var packet = "event:first";
var firstPayload: StringView = payload(packet);
packet = "event:second";
printPayload(firstPayload);
return 0;
}Use ?, or, and or err to handle expected failures directly, without exceptions or hidden runtime behavior.
@error
enum CheckoutError {
EmptyCart,
NotEnoughStock,
}
fun reserveStock(available: Int, requested: Int) Int!CheckoutError {
if requested == 0 {
fail CheckoutError.EmptyCart;
}
if requested > available {
fail CheckoutError.NotEnoughStock;
}
return available - requested;
}
fun checkout(available: Int, requested: Int) Int!CheckoutError {
var remaining = reserveStock(available, requested)?;
println("Order reserved.");
return remaining;
}
fun main() Int {
var remaining = checkout(8, 3) or err {
if err == CheckoutError.EmptyCart {
eprintln("Add at least one item before checkout.");
} else {
eprintln("The requested quantity is not available.");
}
return 1;
};
println("Items left in stock: " + toString(remaining));
return 0;
}Call C libraries through FFI and introduce Zap to an existing codebase one component at a time.
@repr("C")
struct LegacyJob {
id: Int32,
priority: Int32
}
ext fun qsort(
base: *Void,
count: Int,
elementSize: Int,
compare: *fun(*Void, *Void) Int32
) Void;
// qsort calls this Zap function using the C ABI.
@extern("C")
fun compareJobs(left: *Void, right: *Void) Int32 {
unsafe {
var a: LegacyJob = *(left as *LegacyJob);
var b: LegacyJob = *(right as *LegacyJob);
if a.priority < b.priority { return -1; }
if a.priority > b.priority { return 1; }
}
return 0;
}
fun main() Int {
var jobs: [3]LegacyJob;
jobs[0] = LegacyJob { id: 101, priority: 30 };
jobs[1] = LegacyJob { id: 102, priority: 10 };
jobs[2] = LegacyJob { id: 103, priority: 20 };
unsafe {
var comparator: *fun(*Void, *Void) Int32 = compareJobs;
qsort(&jobs[0] as *Void, 3, sizeof(LegacyJob), comparator);
}
println("Highest priority job: " + toString(jobs[0].id as Int));
return 0;
}