Mica 7.6.5 finishes what 7.6 began across activations and processes. A task, a generator, a stream and a worker process now take any value a program holds by value: text, arrays and records of them, to any depth. A worker process receives the sockets, pipes and files its task names. And how many carriers and worker processes a program runs is a range the program states and the runtime reports.

C libraries meet Mica as they are written, with their handles, their text and their status codes, and the sqlite library is rebuilt on them. A library is linked only under a version, and a program says which versions it accepts. The editor extension 5.1 shows what a stopped program holds, and runs and debugs a Mica file with nothing to configure.

The release at a glance

SubjectWhat changed
Values cross every activationtasks on carriers, tasks on a process and generators take text, arrays and records to any depth by value; every such value is a stream element
Generators and streams on a processa producer placed on process feeds a stream from a worker, and a lost worker is answered where the stream is read
Descriptors cross to workersthe descriptor type; a task on a process receives the sockets, pipes and files its arguments hold
The scale a program runs at--processes N and +mica processes=N -mica, 1 to 1024 workers beside 1 to 1024 carriers, oversubscription stated
C libraries as they are writtenopaque handles, text from C, status codes, results through a pointer, a thread_safe statement per handle type
sqlite, rebuiltstatements as values, rows by a generator, every column type and NULL, transactions, sqlite’s codes as failures
Versionsa library linked only under its version; requires in mica.project; pkg-config minimums for C libraries
Memory held to accountan overwritten owning slot refused where it loses its cell; the leak report names each cell’s type and line
The editor 5.1what a program holds at a breakpoint; F5 with nothing to configure; the launch card sets how a program starts

Values cross every activation

A task’s arguments were always snapshots: schedule copies them at the moment it runs, so a task never reads a variable its parent changes afterwards. In 7.6.5 the snapshot is the whole value, whatever it holds. A record with a name and a list of scores crosses the way a number does:

task Report(who : Player);
var
    total, at : int64;
begin
    total := 0;

    for at := 0 to Length(who.scores) - 1 do
        total := total + who.scores[at];

    WriteLn("  %ls scored %lld in %lld rounds", who.name, total, Length(who.scores));
end;
player.name := "Ada";
player.scores := new Scores reserve 0;
Append(address player.scores, 12);
Append(address player.scores, 30);

concurrent
    schedule Report(player);

    player.name := "Grace";
    player.scores[0] := 0;
    Append(address player.scores, 99);
end;
  Ada scored 42 in 2 rounds

The task receives its own copy of the text and of the array, made at schedule in memory the task owns and released when the task ends. The same holds for a task placed on a process, for a generator’s arguments, and for every stream element, pulled or through a ring. What cannot cross is a pointer, because it names memory the receiver could not own, and the compiler names the field that holds it. The tasks and generators tutorials walk the rules.

Generators and streams on a process

A producer placed on process feeds a stream from a worker process. The stream is read as any other, and because a worker can end before the stream does, the consumer says what a lost worker means: in the stream’s on lost section, or in the arm of a select that reads it. The compiler asks for that answer where a producer runs on a process (5600, 5602), and refuses it where none does (5601). Tasks on processes shows the whole road, a library’s tasks included.

Descriptors cross to workers

The new descriptor type names an open socket, pipe or file. It converts to and from the machine integers and to nothing else (5603), so a descriptor can never be mistaken for a count or an index. A task placed on a process receives the descriptors its arguments hold: each is duplicated for the worker as it is placed, so a server may close its own copy the moment the task is placed, and a number that no longer names an open descriptor is refused by name.

ListenIpc answers only its own user, and DialIpc refuses a listener that another user opened, both read from the peer’s credentials, so a local socket path cannot be taken over by another account on the machine.

The scale a program runs at

--processes N, or +mica processes=N -mica at the start, sets how many worker processes run the tasks a program places on processes at once, from 1 to 1024. A pool holds 1 to 1024 carriers. A task placed beyond the count waits until a worker ends, and a stream on a process takes no worker slot, because its consumer paces it. Asked with info, a program says what its start resolved and whether the machine can run it all at once:

mica --tasking multicore,4 --processes 2 Scale.mica +mica carriers=32 processes=64 info -mica
"configuration":{"carriers":{"effective":32,"source":"flag","oversubscribed":true},
                 "processes":{"effective":64,"source":"flag","oversubscribed":true}}

The machine here has sixteen processors, so both counts are stated as oversubscribed, and the program runs them in turn. The pool itself got faster on the way: five thousand placements behind two workers complete in under a second.

C libraries as they are written

A C library’s contract now states what its functions really hand over. An opaque handle, a pointer whose layout is the library’s alone, crosses into generators, tasks and stream elements as a value. Mica never makes, reads or releases what it points to (5607 to 5609), and its contract states whether the type is thread_safe, which the data-race checks honour on every road into a task (5610, 5611). Text a C function answers as a const char * arrives as a Mica string. A status code becomes a failure on the failure channel, and a result written through a pointer becomes the call’s result. A generic or generator body that a library exports may call the library’s private routines and use its private types, which cross hidden with the body.

The sqlite library is rebuilt on these, with no C of its own: statements are values, rows arrive by a generator, every column type and NULL is read as it is stored, transactions are part of the library, and sqlite’s own codes arrive as failures.

Versions a build can rely on

A library is linked only under a version, and a program says which versions of each library it accepts, the way Cargo and npm read a requirement:

{
    "sources": ["demo.mica"],
    "contracts": ["../build/sqlite"],
    "version": "1.0.0",
    "requires": {"sqlite": "2.0"}
}

A C library’s contract names its pkg-config package and the minimum it needs, and the build asks the machine’s pkg-config. A link refuses an archive another build made, and a standard library or a runtime floor another compiler built, each by name.

Memory held to account

A store that overwrites the only owner of a cell that nothing released is refused where it loses the cell:

c := new Box;
c.l := new Leaf;
c.l := new Leaf;
obligation error 13110 [13,6]: heap cell is lost here: this store overwrites the owning slot that held
the cell allocated at line 12, which nothing had released, and nothing releases it after - dispose the
slot's cell before storing into the slot, or read it out into a name that disposes it or hands it on

The checked build’s leak report names each cell by the type it holds and the line that made it, Cell, made at HeapLeakTrapsChecked.mica:32:17, 16 bytes, where it used to name an address. A program that ends joins its carriers and gives back the scheduler’s own tables, so a checker finds nothing left behind.

The editor 5.1

Stopped at a breakpoint, or attached while it runs, a program shows what it holds: its cells summed by type with the line that made each, and every region block as a gauge of its capacity over a strip of its cells.

The Mica Runtime view’s Memory section at a breakpoint: what the program holds in one sentence, its cells by type with the line that made each, and its region block as a gauge over a strip of its five cells

F5 builds and debugs the Mica file in focus with no launch or task file. The launch card above a program sets the runtime flags and arguments it starts with, and Run, Debug and F5 all start the program that way.

Upgrading

Two things a 7.6.0 build accepted are refused by name in 7.6.5, each with what to write instead:

  • A build from a mica.project states the project’s version, as "1.0.0"; a program compiled from its sources with flags alone, or run as a script, needs none.
  • A store that loses a cell by overwriting its only owner is refused (13110), where 7.6.0 compiled the leak.

The packages and the commands that install them are on the install page.