zo iNiTiATiON SPEECHES

Initiation

An initiation to zo.

For Andrea Le Saint And those who refuse the uniformity of software.

Translated by ...

invisageable & the compilords First edition · 2026 · zo version 0.3.11

« Why accept slow compilers? Just make them faster. » — Jonathan Blow

compilords©

install

A short setup before we open the first page. Two commands, two minutes.

get the binary

« Simplicity is a prerequisite for reliability. » — Edsger W. Dijkstra

curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/invisageable/zo/main/tasks/zo-install.sh | sh

The script downloads and extracts the zo compiler into bin/zo and adds it to your PATH so zo is reachable from any shell.

verify

Confirm zo is reachable from your shell.

zo --version

You should see zo x.x.x. The number depends on the latest release.

trouble?

Drop into the discord or open a GitHub issue — fastest path to a fix.

You’re ready. Turn the page.

preface

Par où commencer ? J’manque les mots… tellement ce sujet me fait tourner en bourrique. Je ne sais pas pour toi, mais ce simulacre informatique est de plus en plus faillible. Prends par exemple, les outils qu’on utilise chaque jour: compilateurs, exécuteur de tests ou les éditeurs de code — la plupart sont morts durant le générique de début de film, même si, leurs créateurs vont te convaincre que: “T’inquiètes, c’est rapide !”, puis tu testeras et te rendra compte que ce songe t’a bercé d’illusion.

Maintenant, par dessus, on nous sert des interfaces utilisateurs aux allures de bachi-bouzouk. Je te rappelle que ce sont ces outils qu’on nous force à utiliser chaque jour. Tu te lèves le matin et BIM tu dois utiliser un arrière guichet qui n’a pas été entretenu depuis des années. Pas de syndic, pas de régie, la façade est jonchée de dégueulis de pigeons.

Toutes ces interfaces se ressemblent, comme si les créatifs avaient été balancées en dehors des entreprises comme Jazz. Cette uniformisation du design, de l’innovation est déplorable à vivre. En 76, durant les années dix-neuf cents, les deux Steve (Jobs et Wozniak) avaient compris que créatifs et techniciens se devaient de travailler comme cul et chemise pour le bien de l’artisanat afin d’offrir des créations en avance sur leur temps.

Comme les temps changent, il est préférable d’aller de l’avant. C’est pour ces raisons que j’ai décidé de suivre les traces de mes pairs. T/F Jonathan Blow, Graydon Hoare, Mike Acton, Victor Bret et mes compilords. C’est pour ces raisons que j’ai créé zo, comme eux, j’suis fatigué et j’en ai marre de subir.

Cette initiation va te permettre de voir qu’il y un autre champ des possibles qui nous attends et que nous devons pas nous faire marcher sur les pieds par le mainstream. C’est avant tout une question d’indépendance.

« Voici ce que ça donne quand on se met au travail. »

prologue

Si tu es encore là, c’est surement parce que tu es convaincu que les logiciels devraient être de meilleur qualité. Accepter leur médiocrité c’est se soumettre face aux dictats des commités d’exécution qui nous imposent leurs produits par vague de marketing intensif.

Est-il possible de proposer quelque chose de différent ? Si zo est David et qu’ils sont Goliath, alors zo se doit d’exister pour faire le pont entre le haut niveau et le bas niveau. L’écosystème zo va améliorer le confort des développeurs. Est-ce que tu t’imagines ne plus avoir besoin d’atttendre des secondes, voir même des minutes juste pour savoir si ton programme est correct ? Ou encore, avoir un éditeur de texte qui te donne le sourire lorsque tu l’utilises.

Quand des programmeurs front-end s’intéressent au bas niveau, ils réalisent vite qu’il s’agit d’un simulacre bien différent. Premièrement, la gestion de la mémoire bordel !

“A part La Mémoire dans la peau, je ne vois pas de quoi tu parles ?!”

On ne va pas s’étaler sur le sujet. Force est de constaer que la boucle d’itération est différente, surtout pour un sans cervelle comme moi. C’est face à plein de petites contraintes comme celle-ci qu’on s’est dit qu’il fallait simplifier le process pour permettre à quiconque venant du haut niveau de prendre du plaisir à créer des applications performantes.

L’idée est vraiment d’améliorer l’expérience lorsque l’on code et de faire en sorte que tu puisses en 2-2 transformer tes idées en code sans friction. Pour cela, avec les compilords, on s’est focalisé sur les minuscule détails qui compte mais que tout le monde fait semblant de ne pas voir. Afin d’ouvrir de nouvelles dimensions dans lesquelles nos pensées se transforment en une série de zéro et de un, sans renier au plaisir.

Que tu sois entrain de développer un outil de haute performance ou une p’tite web app, tu devrais pouvoir le faire avec la même logic, la même syntaxe — zsx. L’extension de syntaxe zo va te permettre d’avoir le control total sur ton programme. En plus d’avoir un langage de programmation, tu as en plus une syntaxe similaire au HTML pour créer des applications doper au GPU comme jaja.

JOiN THE DEVOLUTiON.

introduction

This guide is your initiation to zo. Each chapter builds on the previous one — read in order on a first pass, jump around once you know the basics.

how to use this guide

Every lesson is a quick snapshot of a zo program. Read the doc-comments (-!), they provide explanation and describe all the concepts that you need.

-! Hey, I'm a doc comment, read me to understand
-! what's going on in the snapshot program.
-- And me I'm a line comment, mostly introduced within the program.
-*
From my side I'm a block comment, I'm happy to help for details that matter
*-

In zo, each program has to contain an entry point:

-- `fun` declares a function. 
-- `main` is the entry point — the first piece of code that runs.
fun main() {
  -- This program does nothing... yet.
}

That’s it. Turn the page.

hello

-! Let's start with a simple program. In this lesson,
-! we learn how to print `hello, hacker`. Unlike
-! most programming language, zo uses `showln` instead.

fun main() {
  -- There are several builtin functions in zo such as `show`, `eshow`,
  -- `eshowln` for printing.
  -- 
  -- In our case, we call `showln`. This tells the compiler to display,
  -- the value passed as argument with a newline at the end.
  showln("hello, hacker");
}

-! ## the capstone.
-!
-!   - every programs must have a `main` function.
-!   - `showln` is a builtin. No need to import it.

primitives

numbers

Programming is just moving data around. In zo, data comes in a few basic flavors called “primitives”.

You don’t need to memorize all of these right now. Just know they exist. The most important thing: zo is smart. It “infers” types so you don’t have to be a keyboard typist just to declare a number.

All snippets in this guide run inside fun main(). Wrap them when you copy-paste.

integers

-! ## the integer family.
-!
-!   signed:    s8, s16, s32 (int), s64
-!   unsigned:  u8, u16, u32 (uint), u64

-- "Hi, I'm `int` — a signed 32-bit integer, the default for any bare
-- number you write. I scale up to s64 if you need more room, and zo
-- supports big numbers natively — `600851475143` just works."
showln(42);
showln(600851475143);

floats

-! ## the float family.
-!
-!   f32: 32-bit (for GPUs/Games)
-!   f64: 64-bit (float/default)

-- "Hey, I'm `float` — a 64-bit double. Add a `.0` and you get me.
-- I also speak scientific: `1.0e10`, `2.5e-3` — same family, different
-- notation."
showln(14.0);
showln(3.14159);
showln(1.0e10);
showln(2.5e-3);

bases

-- "We're integers in disguise — same value, different notation. The
-- prefix is just how *you* write us; `showln` always prints decimal."
showln(0b11110000); -- binary       → 240
showln(0o77);       -- octal        → 63
showln(0xff);       -- hexadecimal  → 255

parse modifiers

-- "Same as the prefix forms, just inline shorthand."
showln(b#30); -- binary       → 24
showln(o#75); -- octal        → 61
showln(x#76); -- hexadecimal  → 118

strings

-- "Hi, I'm `str` — a string literal. I live in the binary's read-only
-- data section, so I cost nothing at runtime."
showln("JOiN THE DEVOLUTiON.");

chars

-- "And me, I'm `char` — a single Unicode scalar wrapped in single quotes."
showln('z');

bytes

-- "Call me `byte` — raw byte value, written with backticks. No Unicode,
-- just the eight bits."
showln(`z`);

booleans

-- "Hey, we're `bool` — only `true` and `false`. No 'truthy' or 'falsy'
-- mind games here."
showln(true);
showln(false);

variables

Data needs a name. In zo, you have three ways to name a value: val for constants, imu for immutable locals, and mut when things change.

Pick the least powerful one that works — that’s the zo way.

constants

-- "Hi, I'm `val` — your compile-time constant. I never change, and I
-- need an explicit type (you can't infer me). The compiler inlines me
-- everywhere I'm used: no stack slot, no runtime cost. I work at the top
-- level or inside a function — anywhere a name is welcome."
val VERSION: str = "1.0.0";
val MAX_HEALTH: int = 100;

fun main() {
  showln(VERSION);
}

locals

immutables

-- "Hey, I'm `imu` — your immutable local. Set me once, read me many.
-- I'm the default for 90% of your variables; I make code easier to read."
imu name: str = "johndoe";
showln(name);

mutables

-- "And me, I'm `mut` — your mutable local. I can be reassigned. Reach
-- for me only when something genuinely changes over time."
mut health: int = 22;
showln(health);

-- Reassign a `mut` like this:
health = 50;
showln(health);

shadowing

-- "Call me `shadowing` — I let you re-declare a name in the same scope.
-- Each declaration creates a new variable; the old one is untouched."
imu x: int = 40;
imu x: int = x + 1; -- shadows; new x is 41
imu x: int = x + 1; -- shadows again; new x is 42
showln(x);          -- 42

In this lesson, we wrote every type explicitly (like : int). In practice, you’ll rarely need to. zo can almost always figure it out. We’ll stay explicit for now to help you learn, but soon we’ll let the compiler do the heavy lifting in Inference.

-! ## when to use what?
-!
-!   `val` — Global constant. Known before the program even runs.
-!   `imu` — Immutable local. Set once, read many. (The Default).
-!   `mut` — Mutable local. Changes over time.

interpolation

Numbers are useless if you can’t show them. In zo, you drop values directly into strings with {variable} — no format functions, no concatenation.

Interpolation does not allowed expressions, like binop, function calls, etc. It needs the variable name.

-- "Hi, I'm `{}` — string interpolation. Wrap any in-scope variable in
-- braces and I expand it inline at compile time. No runtime parsing,
-- no extra allocation."
imu name: str = "johndoe";
imu hp: int = 100;
showln("hero: {name}, hp: {hp}");

multiple values

-- Interpolate as many as you like in one go.
imu x: int = 10;
imu y: int = 12;
showln("position: {x}, {y}");

under the hood

showln("hp: {hp}") is NOT a runtime format call. The compiler desugars it:

show("hp: ");
showln(hp);

Three things this buys you: zero allocations, zero runtime parsing, zero surprises. As fast as writing the calls by hand.

try this

  • Interpolate a variable that hasn’t been declared. Watch the compiler protect you.
  • Interpolate a float and a bool — any primitive works.
-! ## the capstone.
-!
-!   - any in-scope variable can be interpolated.
-!   - works for any primitive type.
-!   - desugared at compile time — no runtime cost.

operators

Operators are how you transform values. zo keeps them small and predictable — the same five arithmetic operators you’ve used everywhere, plus reassignment and a handful of shorthands.

arithmetic

-- "Hi, we're the arithmetic operators — `+`, `-`, `*`, `/`, `%`.
-- Same precedence and associativity as math: multiply and divide bind
-- tighter than add and subtract."
imu hp: int = 100;
imu attack: int = 15;

imu power: int = hp + attack;   -- 115
imu damage: int = attack * 2;   -- 30
imu rest: int = 10 % 3;         -- 1 (modulo: remainder)
showln("power: {power}, damage: {damage}, rest: {rest}");

reassignment

-- Reassign a `mut` with a plain `=`. The variable's type stays fixed;
-- only its value changes.
mut current_hp: int = 100;
imu damage: int = 25;

current_hp = current_hp - damage;
showln("hp: {current_hp}"); -- 75

compound assignment

-- "And me, I'm compound assignment — `+=`, `-=`, `*=`, `/=`. Just
-- shorthand for `x = x + y`. Read-and-write in one shot."
mut current_hp: int = 100;

current_hp -= 25; -- damage
showln("hp: {current_hp}"); -- 75

current_hp += 30; -- heal
showln("hp: {current_hp}"); -- 105

current_hp *= 2;  -- berserk
showln("hp: {current_hp}"); -- 210

try this

  • Use % to detect even numbers: showln(10 % 2);.
  • Try current_hp /= 0; and watch the compiler/runtime react.
-! ## the capstone.
-!
-!   - arithmetic: `+ - * / %` — same rules as math.
-!   - reassignment: `=` — only on `mut` variables.
-!   - compound: `+= -= *= /=` — shorter spelling, same result.

strings

Sequences of bytes you can store, combine, and index. zo string literals live in the binary’s read-only data section — no heap allocation, no copy at startup.

-- "Hi, I'm `str` — a string. I'm immutable; once created, my bytes
-- never change. Reach for me anywhere you need text."
imu greeting: str = "hello";
imu name: str = "johndoe";
showln(greeting);

concatenation

-- `++` joins two strings. With variables: a fresh string at runtime.
-- With literals: folded at compile time — zero runtime cost.
imu greeting: str = "hello";
imu name: str = "johndoe";
imu full: str = greeting ++ ", " ++ name ++ "!";
showln(full); -- hello, johndoe!

imu title: str = "the " ++ "devolution"; -- folded at compile time
showln(title); -- the devolution

The originals are untouched — concatenation produces a new string, never mutates an input.

indexing

-- `s[i]` returns the `char` at byte position `i`. O(1) — a single
-- byte load, bounds-checked at compile time when the index is known.
imu greeting: str = "hello";
showln(greeting[0]); -- h
showln(greeting[4]); -- o

under the hood

zo strings are length-prefixed: [len:u64][bytes][null]. The length is always known, so there’s no terminator scanning, no strlen walk. Indexing, slicing, and length lookups are all O(1).

try this

  • Concat three variables into one sentence.
  • Try "hello" ++ 42 — the compiler stops you on type mismatch.
  • Build a multi-line message with ++ and "\n".
-! ## the capstone.
-!
-!   - `str` is immutable; operations return new strings.
-!   - `++` concatenates; literal-only forms fold at compile time.
-!   - `s[i]` is O(1) char access, bounds-checked.

chars

-- chars

bytes

-- bytes

arrays

-- arrays

tuples

-- tuples

epilogue