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:
| Namespace | Coverage |
|---|---|
cstd | stdio, stdlib, string, math, ctype, time |
posix | unistd, socket, fcntl, errno, signal, time, process, filesystem |
linux | stat, 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.