Skip to content

FFI & External Interface

Use extern declarations to call external symbols such as C library functions or system APIs. When using FFI, make sure your parameter types, memory layout, and resource cleanup match the external API.

extern {
public Int puts(UInt8[*] text);
public Int open(UInt8[*] path, Int options);
public Int errno;
}

Single declarations can use top-level modifiers:

extern public Int puts(UInt8[*] text);
public extern Int errno;

C-style string pointers use UInt8[*]. A string literal in a UInt8[*] context can be emitted as null-terminated read-only data:

extern public Int puts(UInt8[*] text);
puts("hello from Jiang");

When an API needs a length, use a slice or an explicit length parameter:

extern public Int write(Int fd, UInt8[] buf, Int count);

T* is a single-object raw pointer for FFI, ABI, and low-level code:

Int value = 42;
Int* raw = value$.ptr();
Int copied = raw$.get();

Writing through a single-object raw pointer requires a mutable pointee:

Int! value = 0;
Int!* raw = value$.ptr();
raw$.set(42);

T[*] is also a raw pointer form. It is useful for C buffer parameters:

extern public Int read(Int fd, UInt8[*] buf, Int count);

T* is not used for free position movement like a C pointer. Use T[*] for position-based access into contiguous memory. T[*] has no length. Wrap it with a length field or use T[] when Jiang code needs a length-bearing view.

When wrapping external resources, make ownership explicit:

struct CBuffer {
UInt8[*] data;
Int length;
deinit() {
self.data$.free();
return ();
}
}