Start here — from nothing to your first debugged program, then onward.
One clone is the whole setup.
mica-lang/mica-container is the
starter for Mica: the dev container, the whole example suite, the benchmarks, F5
debugging across every one of them, and the working files this series is
written against.
git clone https://gitlab.com/mica-lang/mica-container.git
code mica-container # then: Reopen in ContainerNothing is installed on your machine but Docker and VS Code. If you would rather not clone anything, part 1 below builds the same setup from four files you paste yourself.
The tutorial series
A guided path from a first program through the type system, the memory model and the concurrency model — written against the shipping compiler, with every example compiled and every command run before it is published. Each tutorial uses one example, and the examples live in the tutorial repository.
The path grows a section at a time. Within a section the order is the reading order; between sections, a tutorial says at the top what it assumes.
Getting started
| Part | Tutorial | You end up with |
|---|---|---|
| 1 | Get started with Mica | a dev container, your first program, and a debugger session — breakpoints, variables, stepping |
| 2 | The shape of a Mica program | the four parts every program has, why nothing is ambient, and a format string checked before the build |
| 3 | Types that change, and what it costs | when a value widens on its own, when you must write as, and what a narrowing cast does to a number that will not fit |
Alongside them: installing Mica, the project file, Mica as a scripting language, and the two small features every program leans on — initializers, and the leave family.
Values and data
| Tutorial | You end up with |
|---|---|
| Values, and arrows drawn by hand | what an assignment copies — everything — and the one construct that shares: a pointer created with address, dereferenced with value, visible at every call site that can change your variable |
| Records, arrays, and bounds you choose | shapes named once in type, matrices as one type with two ranges, copies that reach all the way down — and an index checked at compile time or trapped at its named line |
| Dynamic arrays: growth under the value rule | Append and Length, jagged tables spelled as what they are, and an assignment that still copies — so no callee can grow your list behind your back |
| Conformant arrays: bounds as parameters | one routine for fixed arrays of any bounds, a constant view that provably cannot write, and a pointer view consented to with address at the call |
| Sets: membership as a value | set of a domain you named, the + - * algebra, the recovery-set idiom every recursive-descent parser needs — and bitset[N] when the positions are raw |
| Maps: two reading moods, one value rule | a typed container where Get traps on the key you promised was there, Has/GetOr ask first, snapshots walk in insertion order — and assignment deep-copies, no hidden sharing |
| Bit records: bits with names | typed fields packed into exactly N bits, at pins the compiler proves against the derived layout, and the masked case whose arms read like the datasheet’s command table |
Strings
| Tutorial | You end up with |
|---|---|
| Text: the value, the builder, and the window | the immutable string value that counts runes, the unit whose verbs answer new strings, the builder for the loops where + would copy — and the borrowed window that tokenizes with zero allocation |
| UTF sources: any script, one meaning | identifiers in any script with nothing special about them, rune counts no encoding can change, and the build-time encoding choice whose entire porting cost is one letter per format specifier |
Files
| Tutorial | You end up with |
|---|---|
| Files: the typed file and the failure channel | text out and back through one builder, a missing file as Enoent by name, byte positions you can ask for — and the two error kingdoms drawn through one surface |
| Typed transfers: whole values, and a file as an array | WriteValue/ReadInto sized by the type itself, the plain constraint that refuses to write a heap descriptor’s bytes, and Seek arithmetic that indexes a file of records like an array |
| Paths and directories | the paths unit as pure text algebra — total, failure-free, industry semantics verb by verb — and the directory walk where a path meets the filesystem and its failure channel |
Memory
| Tutorial | You end up with |
|---|---|
| Memory classes: hosted, and a fixed arena | the same source under the OS heap and under one fixed block — five thousand activations through a 16 KiB arena, and a budget that fails loudly at its named line |
| Heap, end to end | an allocation as an obligation with exactly four discharges, use-after-free and double-free as compile-time reports, and the checked tier guarding what no proof can reach |
| Ownership, borrowing and alias | one owner per cell, alias as the checked word for everyone else, and the back edge that gives owned structures parents without a cycle of owners |
| What the compiler proves about your heap | the fourteen-row table: every classic heap bug and its exact fate — a refusal or a named-line trap — each produced by a real build or run |
| Defer, end to end | cleanup registered beside the resource, run newest-first at the exit with exit-time values — and the exact rules for early leaves and loops |
Errors
| Tutorial | You end up with |
|---|---|
| The failure channel: errors as values | a function that admits it can fail in its signature, four clauses at the call site checked at compile time — and cleanup plus a propagation trace riding the failure exit for free |
| Error domains: the type behind the failure | a domain that loops and indexes like any ordinal, walls that keep each layer’s failure story its own, conversion as a translation table the compiler completes — and -1-and-errno lifted into codes at the C boundary |
Programs in the large
| Tutorial | You end up with |
|---|---|
| Generics: one algorithm, many types | the gen clause with thirteen capability words, constraints that check the body and the call both ways, and monomorphization proved by an int64 that would not fit an int32 |
| Units and libraries: surfaces, by declaration | exp as the API decision, one import rule with no special cases, and a library whose contract the compiler emits so consumers can never drift from the source |
Concurrency
| Tutorial | You end up with |
|---|---|
| Tasks and the task tree | concurrency where the block is the lifetime — a join no exit path can skip, arguments that are snapshots, and cancellation that still runs your cleanup |
| Generators and streams | a body that produces values one at a time and suspends between them, an instance you can pause and resume, and pipelines that compose |
| Carriers, multicore and busy loops | one thread or many as a build flag: what stays exact when you switch, and why a compute loop with no suspension point still gives way |
| Data-race freedom, proved at compile time | the rule behind synchronized, the two holes it closes that most languages leave open, and an honest account of its edges |
| Channel streams: the push half | the same generator body scheduled as a producing task behind a bounded ring — fan-in, concurrent pipelines, select with a timeout, and the one exclusivity rule that keeps it all lock-free |
The boundary, and the debugger
| Tutorial | You end up with |
|---|---|
| Mica calls C: a contract, not a header | a C library declared once in a schema-published JSON contract, lifted into Mica with full type checking at every call — scalars, packed aggregates and strings crossing both ways with no adapter |
| C calls Mica: an archive and a naming rule | a plain C program linking a Mica archive like any static library — the target-name linkage rule, the shared ABI story told from both ends, and no runtime to initialize |
| Mica calls Linux: the kernel, without the -1 | POSIX and Linux through contracts embedded in the compiler, every system call an honest fails function — the errno dance compiled, never written |
| Debugging across the boundary | one gdb session over two languages: the Mica→C→Mica backtrace, both specializations of a generic inspected with their concrete types, the full VS Code setup — every transcript a real captured session |
Deep dives
Build a compiler with Mica — a complete working compiler, small enough to read in an afternoon, taken apart a piece at a time and rebuilt into native code. Eleven chapters and Wirth’s 1975 original.
The advanced series is complete: fourteen tutorials across values, memory and concurrency, every example compiled, run and validated on both architectures before publication.
If you teach, or are working through Mica yourself and find a gap, we would like to hear about it: info@mica-dev.com.