Mica 7.6.0 is the release where Mica’s mathematics comes home to the idea
Mica started from. Mica was made to reuse the whole C world with ease: a C
library is one import away, its functions are called as a C compiler calls
them, and nothing C already does well is built a second time. In 7.6 the
mathematics follows the same rule. On the processor, Mica computes with the C
library. On the GPU, it computes with NVIDIA’s own compiler, NVIDIA’s own
mathematics and cuBLAS. And every number a program writes means what C says it
means, at every width from int8 to float64, with float16 and bfloat16
beside them.
This is the one change of direction in this release, and it is a return to the principle that made Mica what it is. The measure is plain: where Mica’s arithmetic and C’s meet, GCC and Clang decide what the right answer is, and the release’s gates compare every operation against them.
7.6 is also the first public release since 7.5.0, so it brings everything built in between: sum types, tasks that run in another process, a program that describes itself and answers a protocol while it runs, routines that promise never to touch the heap, one call stack across Mica and C, and the editor extension 5.0.
The release at a glance
| Subject | What changed |
|---|---|
| Mathematics on the C library | Exp, Ln and Tanh are libm’s functions in the operand’s own width; float32 and float64 arithmetic gives GCC’s and Clang’s result to the bit |
| Numbers mean what C says | integer and real constants exact until their use, rounded once where they are used, C’s rule for operations over real constants |
float16 and bfloat16 | stored, converted and computed with one rounding per operation, and passed to C as the platform’s calling convention lays them down |
| The GPU on NVIDIA’s libraries | CUDA C compiled on the machine by NVRTC, NVIDIA’s mathematics on the device, matrix products on cuBLAS, the driver found when the program starts |
| Sum types | enumeration cases with named field sets, built, matched and checked for coverage |
| Tasks on processes | schedule T(args) on process runs a task in a worker process of the same program |
| A program that describes itself | mica --inspect, +mica info -mica, and the runtime protocol |
| Heapless routines | heapless promises a routine never touches the heap, checked through every call |
| Memory | storage reused in loops and through pointers, a fixed arena that reuses what it is given back whatever its size, a checked build that traps on a leak, an analysis that follows a cell into a container and out again |
| Debugging across Mica and C | one call stack, stepping in both directions, on both architectures |
| The editor | extension 5.0: every stage of a compilation made visible, and a language server that answers from the text on screen |
Mathematics on the C library
On the processor, Exp, Ln and Tanh are calls of the C library, as a C
compiler emits them: expf, logf and tanhf for float32, and exp,
log and tanh for float64, each in the operand’s own width. Sqrt and
FusedMultiplyAdd stay one instruction each, which is what a C compiler makes
of sqrt and fma. A Mica program and a C program that compute the same
formula on the same machine get the same bits.
The same holds for the arithmetic itself. Every float32 and float64
operation, computed at run time or folded by the compiler, gives the result
GCC and Clang give at -O2, on both architectures and at every optimization
tier, and cases in the release gate hold every one of them to it. A float32
literal is read once at float32’s width, as C’s f suffix reads it.
The language’s mathematics lives in one namespace, the math unit. A math
word imported from somewhere else is pointed there by name:
imp Sqrt : std;The compiler answers: 'Sqrt' is not exported by 'std', but 'math' exports it: write 'imp Sqrt : math;'.
The one numerics promise is C’s own: the same program on the same machine gives the same result, run after run.
Numbers mean what C says
A constant in Mica keeps its exact value until its use decides its type. An
integer constant is exact, so u8 := u8 + 300 is judged once, where the
addition meets its operand, and WriteLn("%d", i32 + 3000000000) prints the
value you wrote. A real constant is exact too, and rounded once where it is
used. An operation over real constants rounds per operation as C does, so
0.1 + 0.2 is 0.30000000000000004, the answer every C programmer already
knows.
A constant beside a float operand takes that operand’s type, again as in C:
f32 * 0.1 multiplies in float32. And a conversion that can lose an integer
is written where it happens:
f := i64 as float64;int64 and uint64 hold integers a float64 cannot represent exactly, so
the conversion is spelled out, as Go, Rust, Ada and Zig spell it. The refusal
of an unwritten one says what to write.
float16 and bfloat16 join the family. Both are stored, converted and
computed with one rounding per operation, and they cross to C as the
platform’s calling convention lays them down: in the low sixteen bits of a
vector register, and in records as the convention classifies them, which on
arm64 is AAPCS64, as Clang passes them. GCC on arm64 passes a record of
bfloat16 values in an integer register instead, and
Known limitations
names the roads that work. More than seven
thousand computed rows compare every half-precision operation with what GCC
and Clang compute.
The GPU on NVIDIA’s libraries
Code placed on the GPU is rendered as CUDA C and compiled on the machine by NVRTC, NVIDIA’s runtime compiler, for the exact card the program runs on. The mathematics on the device is NVIDIA’s own. Matrix products run on cuBLAS, with a stream-ordered memory pool beneath them. The program opens NVIDIA’s driver, NVRTC and cuBLAS when it first touches a device, so a device program links without the CUDA libraries, and one binary runs on every NVIDIA card from compute capability 7.5 up.
The device runs are part of the compiler’s own test corpus: each one is a case that runs on a GPU host and states its reason where no GPU answers. The GPU, without kernels is a first device program in one page, and Train your own GPT trains a model on the card.
Sum types
An enumeration’s cases carry named field sets. A value is built with its
fields, a case arm binds a read-only view of them, is tests one case, and
the compiler checks that every case is covered. A field set holds plain
values, strings, and dynamic arrays of those, each copied and given back by
the case the tag names. The walk is Sum types.
Tasks, processes and the runtime
schedule T(args) on process runs a task in a worker process of the same
program, from a block below the root, from a library, and from an importer of
a library’s task, with arguments of any size. A concurrent block that places a
task on a process answers a lost worker in on lost, and it carries one
on fail section for each error domain its tasks can fail.
Every linked program, archive and shared object carries its manifest: mica --inspect prints which compiler, platform and string encoding built it
without starting it, and a running program prints the same with
+mica info -mica, beside the configuration its start resolved. With
+mica rtp=listen -mica, a program opens an owner-only socket and answers the
runtime protocol: its manifest, its
configuration, its task tree, suspend and continue, cancelling a task’s scope,
and its memory readings. The editor’s runtime view draws all of it live.
The process unit starts other programs with posix_spawn and close-on-exec
pipes, reads and writes the environment, and supervises what it started; the
flags unit declares a command line before it reads it. One timer serves
every sleeping task.
Heapless routines
The word heapless promises that a routine never touches the heap, and the
compiler checks the promise through its calls, its imports and the callbacks
it hands on. A signal handler slot takes only such a routine, and refuses one
that waits or locks. It is the language’s road to code that runs where no
allocator exists; Mica on bare metal shows it
running as the interrupt handler of a small kernel.
Memory
A string or an array stored into a variable, a field or an element reuses the storage it replaces, in place when it fits and from its region’s released cells otherwise, so a loop that stores over the same place runs in constant memory. A value written through a pointer does the same: it lives in the scope that holds the storage, for as long as that storage lives, so a procedure that writes through a pointer parameter and a map whose string values are rewritten under the same keys both run in constant memory.
Under a fixed arena, released storage is reused whatever its size: what comes back is joined to its free neighbours, and what is handed out is split from a larger run. A program whose values change length — a table rebuilt at a new size every round — runs in a budget its live set fits.
A Mica program does not leak unnoticed: what the compiler cannot prove, the checked build traps. At a checked program’s end the runtime walks every cell never released and stops with their sizes and a count. The analysis follows a cell into a container’s owning slot and out again, so releasing it a second time, reading it after its container released it, and placing one cell in two owning slots are refused at compile time, each by its rule.
Debugging across Mica and C
A backtrace, a frame walk, step and finish cross between Mica and C at any
depth, on both architectures, with each frame’s variables in its own language.
Strings print as their text in gdb, and a debugger’s first stop in a routine
is its first statement. The editor turns this into one call stack: set
breakpoints in both languages and step between them.
The editor extension 5.0
The Mica extension for VS Code reaches 5.0 with this release. It opens the compiler to you: every stage of a compilation becomes a listing you can read, click through and draw, from the tokens to the placement of every value in registers and frame. The language server answers from the text on your screen, saved or not. Its own post tells the whole story.

The picture is one moment of this release standing together: a tensor and a tape in the source, a generic routine compiled at the type it is called with, a task pool of four carriers, locals and registers read live, and a console whose breakpoints were met in Mica and in the C library beneath it.
Changes to note
int64anduint64becomefloat64only when written withas float64.- A subrange whose bounds lie in
2^31 .. 2^32 - 1takes anint64base, so its storage is eight bytes and an unsigned print specifier over it becomes a signed one. f64 := f32 * 0.1multiplies infloat32and widens the product, as C does.--stack-sizeis the one flag for the stack; the stack it states is the frame ceiling.- On AMD64, the baseline is an x86-64-v3 processor, with AVX2 and FMA3, from 2013 or later.
- A leading sign belongs to the whole selected path:
-b[1]negates the element, as in Pascal, C and Go.
apt changelog mica lists every item, with the diagnostics that are new in
this release.
Getting it
The Debian packages for AMD64 and AArch64, the container image and the editor extension 5.0 are published with this release. The install page has every road.