vision
Install

Language reference

Host and C interop

Vision meets C through five boundaries — a sealed raw-C section, library discovery, verb-to-C bindings, and host exposure in each direction — and links peer Vision files for reuse. Every crossing stays visible, and the compiler never silently infers what happens across it.

Every rule below describes the current Vision compiler. For the shorter safety model, read Safe by design. The Concurrency reference covers strands and channels, which share the ownership rules at the end of this page.

The host boundaries

Six top-level forms touch the host, and five of them cross into C. by hand: drops raw C into a function verbatim and is the precision escape hatch. this program understands zlib discovers a C library's real surface. A C face binds a Vision verb to one of that library's functions. this program exposes greet to the host publishes a Vision verb on the generated C ABI, and this program receives a context from the host accepts an opaque type the host owns. The sixth, this program links (settings), is not C at all: it pulls declarations from a peer Vision file for reuse.

by hand: sealed C

by hand: opens a sealed section. Its indented body is one raw block the lexer never tokenizes as Vision; the emitter drops it into the surrounding C function unchanged, behind a // by hand — raw C contact, sealed: marker. The body is ordinary C, so comments, loops, and fixed-width types all survive verbatim.

Vision locals are ordinary C variables, and the raw C reads and writes them by name. the count becomes the C variable count; a sealed line may read it, change it, and let the Vision code after the section see the new value. That is the whole point of the escape hatch, and it is also its cost: Vision does not check effects, failure clauses, types, or lifetimes inside the section. The author owns all of it.

Vision's core has only whole (a signed 64-bit int64_t) and byte (0–255). There is no exact-width integer family in the language itself; by hand: is how a program reaches uint32_t and the rest of <stdint.h>.

reference-interop-narrow.viscompiler checked
to begin:
    the count is 4294967301
    the folded is 0
    by hand:
        uint32_t narrowed = (uint32_t)count;
        folded = (int64_t)narrowed;
    say "narrowed: {the folded}"
to begin:
    the count is 4294967301
    the folded is 0
    by hand:
        uint32_t narrowed = (uint32_t)count;
        folded = (int64_t)narrowed;
    say "narrowed: {the folded}"
The sealed line narrows a 64-bit count through uint32_t, which the core language does not have. The raw C reads count and writes folded; the Vision line after it prints folded and the build checks the exact result.
reference-interop-sum.viscompiler checked
to begin:
    the total is 0
    by hand:
        long sum = 0;
        for (int i = 1; i <= 100; i++) sum += i;
        total = sum;
    say "sum: {the total}"
to begin:
    the total is 0
    by hand:
        long sum = 0;
        for (int i = 1; i <= 100; i++) sum += i;
        total = sum;
    say "sum: {the total}"
A C for-loop and a local long live verbatim in the sealed section. Vision sees only the total the loop left behind.

The surrounding source-map directive covers the whole block, so a crash inside the raw C attributes to the .vis line where by hand: appeared. Memory allocated inside a sealed section is not tracked or freed by Vision; free what the section allocates.

Understand a C library

this program understands sndfile asks the compiler to discover a library's real surface by parsing its installed header with the system clang. Discovery records the functions, the soname used for linking (zlib links as -lz), the header path, and the include and link directories. The build then emits the matching #include and link flag. There is no hand-maintained signature block to drift.

Two commands are derived from discovery and never hand-written. vision explain sndfile prints every function the library offers, with the shapes read from the library itself. vision audit program.vis reports, for each understood library, which of its functions the program actually calls inside its by hand: sections — the realized surface, not just the available one.

The library and its header must be installed where clang can find them; discovery fails with a clear message otherwise. Linking still goes through the host C compiler, so a library the build cannot link cannot be used, and this is also how a program reaches a C library for a capability the core language omits (the network reference states the current socket surface and its gaps).

Bind a verb to a C function

A C face declares a Vision verb whose body the compiler generates from a discovered C function. Write to compress is compress, then describe the face with it takes, it gives back, and it fails when clauses. The compiler discovers the real C signature and infers the marshalling — the input byte buffer and its length, the output buffer, the return code — so the author writes no C types. A stateful face names a begin, feed, and finish family and threads an opaque library-owned pointer through those roles. Either way the call site is plain Vision: compress the data returning the packed.

The compiler never silently guesses. If a function's shape is ambiguous or unmappable, it surfaces a specific question and stops. If no understood library defines the named function, it reports no-library-for-c-function; the c-face-* family covers argument and shape problems.

Expose verbs to a host

this program exposes greet to the host marks one Vision verb as callable through the generated C ABI. Compile with --library to emit a host-callable C unit with no main, and --header greet.h to write the C prototypes for the exposed verbs. A host that calls an exposed verb and receives heap-owned text owns that result and must release it; the ownership rule below crosses the ABI in both directions. The host-expose-* diagnostics reject a verb whose shape or parameters are not host-compatible.

Receive opaque host types

this program receives a context from the host declares an opaque type the host hands to Vision. No interior is ever known, and no C library is bound, which makes it the reverse of understands. A parameter named to match resolves to the received type. The name is a single word, like every other named type in Vision.

this program links (settings, main) brings declarations from peer settings.vis and main.vis into the program. Inclusion is flat and order-independent, and names must be unique across every linked file — the same rule as within one file, with no namespacing. The namespaced form this program links (settings as config) reaches those declarations only as config.name and exempts them from the flat-uniqueness check. This is peer Vision inclusion, never a C binding.

Ownership across the boundary

Vision's return rule is precise: a heap-owning value that a verb produces and returns transfers to the caller. A borrowed value that a verb returns—a text parameter, a field, or an item read from a list—is cloned at the return boundary, so the caller owns an independent copy either way. A caller-owned result is reclaimed when it is ignored, overwritten, or leaves its scope. There is no garbage collector on that path.

The same contract crosses the C ABI. An exposed verb that returns heap-owned text hands ownership to the host, which must release it. A C face wraps the foreign call and stores its output in Vision-owned storage, so the result follows the same reclamation rules. by hand: sits outside this tracking: memory the sealed section allocates is not freed by Vision.

A memory: block is the visible opt-in for a lifetime the compiler cannot otherwise prove, such as an owned value stored into a longer-lived field. The compiler requires the block rather than silently switching to hidden reference counting. Safe by design states the same rule in plain terms with a runnable example.