Calling C from a modern systems language usually means one of two things: an unsafe block plus a generated wrapper crate, or a foreign-function bridge with its own build step and its own performance story.

Mica links against C directly, in both directions, with no wrapper layer — and the boundary is typed, so C’s error conventions do not leak into your code.

Error conventions are declared, not repeated

A C function signals failure by returning -1 and setting errno, or by returning NULL, or by returning a sentinel like MAP_FAILED. That convention is declared once, in the interop contract for the symbol. At every call site, the compiler lifts it into the language’s failure channel:

sock := Socket(AF_INET, SOCK_STREAM, 0) on fail use -1;
rc   := Connect(sock, address remote, 16) on fail leave;

No -1 comparison, no NULL check, no errno read anywhere in user code. The imported function simply is a failing function, handled the same way a Mica one is.

Curated contract packs

Contracts ship for three namespaces, verified against real ABIs rather than transcribed from headers:

NamespaceCoverage
cstdstdio, stdlib, string, math, ctype, time
posixunistd, socket, fcntl, errno, signal, time, process, filesystem
linuxstat, signalfd, epoll, file descriptors, inotify, device, timerfd, random, sched

A symbol manifest maps each importable name to its partition file, so the compiler loads and parses only the contracts your units actually import.

Both directions

C calls Mica as readily as Mica calls C. Mica library symbols stay callable from C by name, because the mangling contract uses a separator that is legal in C but cannot be produced by a Mica identifier. A C main can link a Mica archive and call into it directly.

You can step across the boundary in a single debugger session — Mica frames and C frames in one backtrace.

Safety analysis extends across the boundary where it can. A pointer that comes straight back from C carries its C origin, and disposing it is rejected at build time — dispose CellBorrow() fails with analyzer error 5191 rather than handing a C-owned cell to the Mica allocator.

Compiled objects are encoding-specific, and UTF-8 symbols carry a suffix so that importing with the wrong string encoding fails loudly at link time rather than linking the wrong code.

See also