A compiler knows more about your program than it usually says. It proves facts, counts costs, and rewrites what its optimizers can reach — and then it keeps almost all of that to itself, because the only voices it has are the harsh ones: errors that stop you and warnings that judge you.
Mica 7.2.1 gives the compiler a third voice. Remarks are hints from its own
knowledge about your code — be careful here, or do it another way — spoken
only when you ask with --remarks, and never gating a build. The release ships
together with VS Code extension 4.1.0, which puts that voice in the editor, and
with the sqlite library — the first rung of the new
libraries shelf, and the first user of the release’s other new arrival, the
callback kind.
Remarks: what the compiler already knew
A remark exists where Mica is different by design and the difference is worth one sentence. The value model is the clearest case: values copy, honestly and visibly — and sometimes you did not want the copy. Ask, and the compiler says so:
$ mica --compile --remarks --source norm.mica --build build
Remarks:
17: function Norm(sample : Sample) : int64;
^ analyzer remark 5517 [17,15]: the parameter 'sample' copies its whole 32 bytes on every call, and this body only reads it: 'const sample : Sample' passes one address into caller-owned read-only storage instead — the same reading, with no copy at any call siteSix remarks ship at first light, and every one names its alternative in the sentence:
- a by-value record wide enough that
constchanges the mechanism itself — one address instead of the bytes, with the byte count spelled; - a by-value dynamic array the body only reads, where a conformant view borrows the caller’s storage with no copy at any call site;
- a string growing through its own
+inside a loop, where every step copies everything built so far and a stringbuffer builds in place; - a whole wide record assigned name-to-name inside a loop — work through a pointer, or hoist the copy;
- an indexed string walk under utf-8 at the debug tier, where
for c in sreads the same code points in one pass; - an allocation inside a loop under the fixed-arena deployment class, where every iteration draws on a fixed budget.
Each speaker is deliberately narrow: it fires only where its sentence is true and its advice is a mechanical improvement — a body that writes its parameter, a copy outside any loop, a build where the optimizer already rewrites the walk all stay silent. Remarks are deterministic, they never repeat a rule the style documents own, and without the flag the compiler prints not one character more than before.
The flag is -rm | --remarks, it combines with every road including
mica --run, and the command line reference carries its row.
The callback kind
The C world hands out its events through function pointers, and Mica does not
have those: a routine is called with its argument list, never read by name,
and every call graph stays static. Meeting libraries like sqlite honestly —
sqlite3_exec fires a function pointer once per row — produced the third
declared subprogram kind, beside task and generator:
callback CountRow(context : pointer Tally, columns : int32, values : pointer int64, names : pointer int64) : int32;
begin
context.rows := context.rows + 1;
CountRow := 0;
end;
rc := SqliteExecRaw(db, "select reading from m", CountRow, address tally, address sink);A callback is never called from Mica and never a value. Its name stands in
exactly one place — at a callback slot an imported contract declares — the
foreign library performs every firing while the imported call runs, and the
callback’s whole environment is the context record your call visibly hands
over. Everything the callback can touch is on that one line, which is the same
what-you-see-is-what-happens the value model promises everywhere else.
Callbacks at the boundary is the kind’s own chapter, and the contracts reference states the slot form a contract declares.
Libraries cross their contracts more completely
Two things a Mica library writes can now travel through its emitted contract whole:
- An exported generator crosses as the source it is and compiles inside
the importing program — so a library can ship a pull road, and
for row in Rows(q)in your program reads like any local loop. - A borrowed handle keeps its
borrowed pointerspelling across the boundary, so a library wrapping a C resource can answer handles the ownership analysis treats truthfully: your program owes nodisposefor a cell the C side owns.
Both arrived because the sqlite library demanded them, which is what the libraries shelf is for: each rung meets a real library on its own terms, and what the meeting teaches flows back into the language. The notes application tutorial walks the whole road, and the sqlite announcement tells that story in full.
A handful of diagnostics also learned better manners in passing: sentences that once deferred to the future now state the rule on its own terms, with the actionable road named.
Extension 4.1.0: the voice in the editor
The extension pairs with the release and needs nothing configured — update the compiler, and remarks are simply there:
- Remarks in the Problems panel, at the information severity, through the language server the extension already speaks.
- A status-bar counter — a lightbulb that appears only when the open files
carry remarks, clicking through to the Problems panel — and a
mica.remarks.visiblesetting for a quiet session, errors and warnings never affected. - The snippet family returns, written against the current language:
program and library skeletons, all three declared kinds —
callbackincluded — the concurrent block, the pull loop,on fail, records, error domains,case, anddefer. - A new walkthrough step, Meet the remarks: paste one small program, save, and the compiler explains a copy you may not have wanted.
- The grammar knows the
callbackword, arriving with the example that consumes it.
Getting it
The packages for both architectures are on the
download page, the micalang/mica image ships 7.2.1 with the
sqlite example inside, and the extension updates through your editor as 4.1.0.
The changelog carries the
release’s full error report — every new sentence the compiler can now say,
remarks and refusals alike.
What is deliberately not here: remarks from the optimizing tiers themselves —
facts like this guard is provably always true live behind the optimizer and
wait for their own road — and the registered callback class, which a
library stores and fires later, is declared but refuses every binding until it
can be served on the task model’s own terms. Both are stated in their
diagnostics rather than promised in prose.