forty years of libraries
Calling C libraries
You describe what a C function does. The compiler handles the mechanics. You never write a pointer.
The idea
C has forty years of battle-tested libraries: cryptography, compression, audio, databases, image processing. Vision can reach all of them. The mechanism is a face declaration — a description, in plain Vision, of what a C function does. No C code, no pointers, no length parameters, no out-parameters.
The declaration says: this function takes these things, gives back these things, fails when this happens. The compiler — which has already read the C header — maps the Vision description to the actual C signature and handles the conversion beneath the floor.
Single-call face
A function that takes input and returns output in one call uses a simple face declaration:
this program understands blake3 // Declare what the function does — in Vision terms, never C terms: to hash some bytes is blake3_hash it takes some bytes it gives back some bytes // Call it like any Vision verb: to fingerprint, given the contents: the hash is hash the contents answer the hash
this program understands blake3 tells the compiler to find and
bind the blake3 library. The declaration says: "there is a Vision verb called
'hash some bytes', and it corresponds to blake3_hash in C." From
that point, you call it like any Vision verb.
Stateful: begin / feed / finish
Many C libraries use an init/update/finalize pattern — create a context, feed
data to it repeatedly, then extract a result. Vision provides
begin / feed / finish as the vocabulary
for this pattern:
this program understands blake3 // A stateful C API with init/update/finalize: to begin a blake3 hash giving a hasher is blake3_hasher_init it gives back a hasher to feed some bytes to a hasher is blake3_hasher_update it takes a hasher and some bytes to finish a hasher giving some bytes is blake3_hasher_finalize it takes a hasher it gives back some bytes // Use it in plain Vision: to fingerprint, given the contents: begin a blake3 hash giving the hasher feed the contents to the hasher finish the hasher giving the result answer the result
Three separate face declarations, one per C function. Then the call site reads like a sentence: begin a hash, feed data to it, finish it to get the result. The C context object (the hasher) is managed automatically — it lives as long as it is needed.
Failure from C
C functions signal failure through return codes, errno, or output parameters.
The face declaration captures this with it fails when:
this program understands zlib to compress some bytes is compress2 it takes some bytes and a level it gives back some bytes it fails when the input is too large to decompress some bytes is uncompress it takes some bytes it gives back some bytes it fails when the data is corrupt
At the call site, Vision generates the but if failure conditions
from the declaration. You handle them with the standard failure vocabulary —
stop, hand it on, give up.
The by hand: escape
Occasionally a C function is genuinely too unusual to describe with a face
declaration — unusual calling conventions, macro-based APIs, functions that
mutate their arguments in non-standard ways. For these cases only, Vision
provides a by hand: block.
by hand: is a last resort, not a shortcut. It should not contain
loops, control flow, or allocation. If you reach for it, stop and ask: can the
C function be wrapped in a thin C shim that has a normal face?
A well-written Vision program that uses C libraries should have zero or near-zero
by hand: blocks. The face declaration is the right tool for almost
every real C function.