Examples
All 192 programs from the repo, each with exactly what it prints. They are Zag’s tests as well: every one runs and is checked, so they show the language as it is today.
Start here
- Hellohello.zg
- FizzBuzzfizzbuzz.zg
- Collections
collection.fnwrites a function and its dot narrowings in one block (the other kind,collection.handler, is in collection_handlers.zg).collections.zg - GenericsA blank, <T>, filled per use by the compiler.generics.zg
- TestsA
test fntakes nothing and returns nothing;zomp testruns each one.testing.zg - C headers
incl.C.system["…"]reads the system's headers while building, so C's functions need no hand-writtenextern.C.c_headers.zg - Assembly beside ZagInline ARM64 assembly beside the same work in Zag.asm_beside_zag.zg
- A day at a corner shopA longer Zag program, written to be read.corner_shop.zg
Every program
- Addadd.zg
- And runs both
andandoralways work out both sides, left then right: nothing written on the line is skipped.and_runs_both.zg - And then or else
and.then/or.else: the right side is worked out only when the left has not already decided — "A, and then (only if A held) B", "A, or else (only if A failed) B".and_then_or_else.zg - Any widthIntegers of any width, marked as not standard:
not_std.int24/not_std.uint4.any_width.zg - ArgsCommand-line arguments, as C hands them over: MAIN may take 'argc' and 'argv', the program's name first, each word NUL-ended, a null pointer after the last.args.zg
- Argument contextAn argument takes its parameter's type as its context, as a declaration's value does: show[0 minus.wrap 1] wraps at 8 bits, and list.append's value takes the element type.argument_context.zg
- Argument wordsEvery argument after the first says its role: the first, the thing worked on, is bare; each other starts with a word.argument_words.zg
- Assembly beside ZagInline ARM64 assembly beside the same work in Zag.asm_beside_zag.zg
- Bare marksHow other strikes write the path to each
pubthing: every one is covered by a mark on itself, its module or its kind, and the marks that cover it agree.bare_marks.zg - Bin widthsA bin16/bin32 holds what its width holds: a value is rounded to it where it lands (DECISIONS 2026-09-14).bin_widths.zg
- Bitwise operatorsThe boolean words, per bit.bitwise.zg
- Bitwise wrapA bitwise operand must fit the operator's width;
.wraptakes it as its bits instead, as the chip does.bitwise_wrap.zg - Boolsbools.zg
- A length bound on a list
list[T][lo, hi].bounded.zg - Bounded mapA map's count bound, and bounds on the things inside — types composing.bounded_map.zg
- The brain float
brain16.brain16.zg - Brain16 rounds onceA number into a brain16 rounds once, to the nearest brain16.brain16_rounds_once.zg
- Brain16 useful largeA brain16's useful decimal is its shortest form even when large: 2^63 as a brain16 is 9220000000000000000, which fits an int64, not its stored 9223372036854775808.brain16_useful_large.zg
- Bytes into text
to.str.utf8reads a list or array of uint8 as UTF-8, and failsnot_utf8when they are not.bytes_to_text.zg - A C enum
layout.C enum, a number per case as the C header gives it, no data.c_enum.zg - C enum convertA number from C becomes a C enum only through a check.c_enum_convert.zg
- A header in the strike
incl.C["…"], from the strike's root.c_header_local/ · 2 files - C headers
incl.C.system["…"]reads the system's headers while building, so C's functions need no hand-writtenextern.C.c_headers.zg - C struct rangesA range type may be a field of a
layout.C struct.c_struct_ranges.zg - C structsC's structs.c_structs.zg
- C typesC's machine-sized types and enums.c_types.zg
- C variablesC's variables and pointers holding a C enum.c_variables.zg
- CallbacksA capture-free, C-shaped Zag function handed to C.callbacks.zg
- Case filecase_file.zg
- Case isA case says its value with
is, and may do other work first.case_is.zg - Case marksNames are exact unless marked.case_marks.zg
- Case unicodeInsensitive means Unicode's full case folding:
ßmatchesSS,Ématchesé.case_unicode.zg - CharsChar conversions: code by name, text ↔ char and unit ↔ unit as failing conversions.chars.zg
- Check tierscheck_tiers.zg
- Collection handlers
collection.handler: namedotherwiseblocks.collection_handlers.zg - Collections
collection.fnwrites a function and its dot narrowings in one block (the other kind,collection.handler, is in collection_handlers.zg).collections.zg - CommentsA whole-line commentcomments.zg
- Compound change
'i'++;,'i' += 1;and the others spellchange 'i' = 'i' plus 1;, andconcatjoins text,++its symbol.compound_change.zg - ConcurConcur, channels, duration literals.concur.zg
- Constsconsts.zg
- Context stops at a callThe type a value is stored into reaches the arithmetic that makes it, but stops at a call: what
g[…]returns says nothing about the arithmetic in its arguments.context_stops_at_a_call.zg - Context stops at a comparisonThe type a value is stored into stops at a comparison, as it stops at a call: a
boolholds the comparison's answer, and its operands take their width from each other.context_stops_at_a_comparison.zg - A day at a corner shopA longer Zag program, written to be read.corner_shop.zg
- Counting downThe step is its own signed number, not a value the counter takes.countdown.zg
- DeciDeci, IEEE 754 decimal: 0.1 plus 0.2 is exactly 0.3; every operation rounds to the width half to even; trailing zeros are kept (print shows 2.50, print.useful 2.5); a literal…deci.zg
- Deci contextDeci beside other things: a group of bare numbers beside a deci takes its width; a bin's useful form is the shortest at its own width; a deci map key is its value, so 1.50 and…deci_context.zg
- Deci field contextA literal takes its type from where it lands: a struct field's type and an enum case's data type are its context, as a declared variable's is, so
0.45into adeci64field…deci_field_context.zg - Deci moredeci's leftovers: mod.floor takes the divisor's sign, as integer mod.floor; pow takes a whole exponent and rounds like the other operations; a wider deci into a narrower one…deci_more.zg
- Deci writtenText into a deci goes by the value: "1234567.0" is 1234567, seven digits, and a deci32 holds seven, as
to.int32[2.0]is 2.deci_written.zg - Deep callsA call nested 2000 deep in one expression runs.deep_calls.zg
- Div edgesEdges of
div.X/mod.Xon numbers with a fraction.div_edges.zg - Div landsDivision is exact and checked where it lands, as
plus,minus,timesandpoware: the smallest int8 divided by -1 is 128, which no int8 holds, but a print takes the true…div_lands.zg - Div roundingEvery division says how it rounds:
floordown,ceilup,trunctoward zero,nearto the nearest (a tie to even).div_rounding.zg - Div wrapA division that wraps like the hardware:
div.trunc.wrapand the other three give the true quotient, wrapped at the type's width, so the smallest value divided by -1 is…div_wrap.zg - Divisiondivision.zg
- Duration bare
durationbare is std'sstd::duration: std marks everythingbare.optional.duration_bare.zg - Emptyempty.zg
- Enumsenums.zg
- Exact literal
*0.1means "exactly this": a decimal literal marked*is a deci; a plain one is a bin, meaning bin64's answer.exact_literal.zg - Extern block pubLines in an
extern.C { … }block may each saypub: herestrlenis public andwritestays private behind a safe wrapper, as good practice #5 says.extern_block_pub.zg - Extern dataextern.C 'x': T — a C global.extern_data.zg
- Extern rangeA ranged extern return is a contract checked at the door: outside it, the call fails out_of_range.extern_range.zg
- Failuresfailures.zg
- Fallback typeA conversion's fallback takes the conversion's type:
to.deci32['x'] otherwise 0is a deci32 0, and so is 'y'.fallback_type.zg - FFIThe door to the OS.ffi.zg
- FizzBuzzfizzbuzz.zg
- For item typeA loop's item has the list's element type: 'y' is a uint8, so 'y' plus.wrap 10 wraps at 8 bits, and 'x' is an int32 for not.bit.for_item_type.zg
- For lend mutOver
lend.mut 'xs', the loop's element is the list's own element: changing it changes the list.for_lend_mut.zg - For lend mut readInside
for 'x' in lend.mut 'xs', the list may be read once 'x' is used for the last time in that trip, and the read sees the new values.for_lend_mut_read.zg - For no cheat
for no_cheat— "no cheat": every round's work really happens, so the compiler may not replace the loop with its answer (here n(n+1)/2) or drop rounds; SIMD and cores are…for_no_cheat.zg - For para
for paraforces a loop parallel,for seqforces it in order; without either, the prover decides, and a loop that prints stays in order by itself.for_para.zg - The position beside the item
for 'i', 'x' in lend 'xs'— 'i' is 1, 2, 3 … (a uint64, like every position), 'x' the item there.for_position.zg - Format value
format[…]makes the textprint.formatprints: one format language, to print or to make text.format_value.zg - Functions as valuesFunctions as values.functions_as_values.zg
- A generic operatorWritten once for any type that keeps its interface's promises, like a generic fn.generic_op.zg
- GenericsA blank, <T>, filled per use by the compiler.generics.zg
- GeometryThe root of the strike: its items are
geometry::…from outside.geometry/ · 4 files - Gradebookgradebook.zg
- Hello World through CNo std, only CNC, which C calls need.ground_hello_c/ · 2 files
- No std listedNo operators and no printing.ground_only/ · 2 files
- The Ground, Zag's base, aloneNo plugins, no std.ground_practical/ · 2 files
- Hellohello.zg
- Include bytesA file's bytes go into the program while it is built.include_files/ · 5 files
- InputInput and range types.input.zg
- Interface typesGenerics announced after the name, each saying what it accepts.interface_types.zg
- InterfacesA named list of promises about some <T>, announced after the name.interfaces.zg
- Inventoryinventory.zg
- IteratorsA type with its own
nextreturningoptional[…]is walked byfor.iterators.zg - Joinjoin.zg
- Map keysPlain values, text, chars, structs and enums by structure — or a type's own
op equal_toandfn hash(it satisfiesKey), with "equal keys hash the same" a check site the…keys.zg - Keyword fnA keyword may name a function, reached by path, never bare: bare
tois the conversion and baretruethe boolean, so these aremy.to[],my.true[].keyword_fn.zg - Lent twiceOne list may be lent to two parameters at once (both only read it).lent_twice.zg
- Handing back a borrow
-> lent @x T.lifetimes.zg - List arrayA list and an array are different types; nothing converts by itself.list_array.zg
- List fillA list of n copies of one value:
list.fill[value value, count count].list_fill.zg - List item contextA list literal's items take the list's element type as their context, as a declaration's value does: 0 minus.wrap 1 in a list[uint8] wraps at 8 bits, 2 shl 3 in a list[uint32]…list_item_context.zg
- List literal familyA bare literal takes the family of its context, inside a list too: each value lands in an element slot.list_literal_family.zg
- List literal mixedIn a list literal, a bare number takes its family from the other items: the 1 here is a bin, like the 2.5 beside it.list_literal_mixed.zg
- Listslists.zg
- Lists2lists2.zg
- A const in a bodyIts value is known at compile time, nobody owns it (it is written bare, like a top-level const), it is never shadowed, and it is seen only in its block.local_const.zg
- Lockerslockers.zg
- Long arrow
->in a signature and a function type,<-intoprint.weird: the short arrows are the only ones;-->and<--, main from 2026-10-03, are refused, naming the short one.long_arrow.zg - Loopsloops.zg
- Low levelRaw memory from C, bits, a wrapping hash, SIMD, C layout, and the OS through
write.low_level.zg - Match data typeA match arm's data name has the case's type: 'd' is an int32, so not.bit and times.wrap know their width, and 'b' is a uint8, so plus.wrap wraps at 8 bits.match_data_type.zg
- Match valueA
matchthat gives a value: a case whose block holds only a value is that value; a case may still leave instead (return,fail,break).match_value.zg - Mod bin
mod.flooron a bin takes the divisor's sign, as on integers and decis, so an angle stays 0 to 360; C'sfmod(the dividend's sign) ismod.trunc, by name.mod_bin.zg - ModulesModules as blocks in one file (a strike of one root file).modules.zg
- Mutabilitymutability.zg
- Nested matchA
matchalone in a case is a statement; a nested match that is the case's value saysis match ….nested_match.zg - No checks
NO_FUCKING_CHECKS: the fourth tier.no_checks.zg - Not bit fill
simd.fill[value not.bit (5 plus 'v17')]with a uint16 'v17', for a simd[uint16, 8].not_bit_fill.zg - Code for one target
on.targetis chosen when compiling, and a branch it rules out is not compiled at all;on.machineasks the actual machine once, when running.on_target.zg - One-ended rangesA side left out is the type's own limit.one_ended.zg
- One strike under two prefixes
areas::andshapes::are two strikes with their own types, so anareas::Circleis not ashapes::Circle.one_strike_two_prefixes/ · 2 files - Op bang
!is free to declare as a custom operator, as^and|are (operators.md): between two values, declared, it is an operator like any other.op_bang.zg - An operator as a value
op +, handed wherever a function goes.operator_values.zg - Operatorsoperators.zg
- Overflow sitesPlain math (plus minus times pow) is exact, and checked where the value lands: a typed declaration, a
change, an argument, a return.overflow_sites.zg - Ownershipownership.zg
- Owning functionA function that captured with
copyorgivecarries what it captured, so it is owned like a list: copying or handing it on takes a word.owning_function.zg - Phonebookmap[K, V] — a language collection beside list and array.phonebook.zg
- PiThe digits of pi, by the Rabinowitz–Wagon spigot: integers only, no bin anywhere.pi.zg
- Plugins listedEach plugin's words work once the strike lists the plugin: here MCPS's
concur.plugins_listed/ · 2 files - Powerpower.zg
- PowersThis strike lists
c_calls, and the program denies every C call exceptwrite, so its one call towritebuilds.power_deny_except/ · 2 files - Precedenceprecedence.zg
- Precedence levelsA strike gives its operators a precedence:
precedence.low_firstcounts level 1 as the loosest (good practice), each level says how a chain reads, and a language operator in a…precedence_levels.zg - Print auto newline
std::print.useful.auto_newlnends the line itself, so nonewlnis written.print_auto_newline.zg - Print formatstd::print.format — the formatting print.print_format.zg
- Print vs print usefulprint_vs_print_useful.zg
- Print weird
std::print.weird— C++'scout <<, Zag style: each value follows a<-, the arrow pointing into the output, as<-points into a variable ininline.ASM.print_weird.zg - PrintsThe two prints.prints.zg
- Ptr castA pointer seen as pointing at another type:
ptr.cast[T]['p']keeps the address and whether it may write, and changes only what it claims to point at.ptr_cast.zg - Queue
list.removehands the removed element back: no copy, no hole.queue.zg - Rangerange.zg
- Range typesA type with bounds, provably within them.ranges.zg
- Return in matchA
returninside amatcharm lands in the function's return type, never in the declaration the match sits in: the 64-bit shift below is a uint64's, not a uint16's.return_in_match.zg - Scoresscores.zg
- Three separate promisesMut — the value may be changed immut — it may not no_shadow — the name may not be shadowed; it means this variable all the way down Shadowing (
shadow 'a' := …) makes a new…sealed.zg - Shadowshadow.zg
- Shift length itemA list's length is a uint64 and an item has the element type, so either gives a shift its width.shift_length_item.zg
- Shift masked
shl.masked/shr.maskedshift as the chip does: the count is masked to the width (70 on 64 bits is 6) and bits pushed past the width are cut off; no check site.shift_masked.zg - Shl call widthA call's return type gives a shift its width:
g[]is an int8, sog[] shl 1is an 8-bit shift.shl_call_width.zg - Shopshop.zg
- Short arrow
<-feedsprint.weirdone value at a time.short_arrow.zg - SIMDsimd[T, N]: N plain values in one register, the ordinary operators lane by lane.simd.zg
- SIMD fieldsA simd value goes anywhere a number does: a struct's field, a list's element, a parameter, a return value.simd_fields.zg
- SIMD fold shiftA vector folded to one lane gives a shift the lane's width:
simd.max['s']of uint8 lanes is a uint8, soshl 1is an 8-bit shift.simd_fold_shift.zg - SIMD lane shiftA vector's lane has the lane's type, so a shift of it has a width, as a list item does: 's'[pos 2] is a uint64 here.simd_lane_shift.zg
- SIMD lanesA vector's lane is read like a list's item, 'v'[1], 1-based; the wrapping forms work lane by lane at the element's size.simd_lanes.zg
- SIMD mask
simd[bool, N]is a type you can write: a mask, one yes/no per lane, as a vector comparison gives.simd_mask.zg - SIMD ruled outA branch
on.targetrules out is "not compiled at all", so a 256-bit vector there is not judged against this 128-bit target; the hand-written fallback runs.simd_ruled_out.zg - SIMD shuffle
simd.shufflerearranges lanes: the vector, then its new order as lane numbers, which must be fixed numbers known when compiling.simd_shuffle.zg - SIMD sum forms
simd.sumis worked out in full and checked where it lands, as any plain number;simd.sum.lanechecks it at the lane's type, andsimd.sum.wrapwraps it there as the chip's…simd_sum_forms.zg - SIMD tailThe leftover end of a SIMD loop:
simd.load.someloads k items and leaves the other lanes zero;simd.store.somewrites only the first k lanes.simd_tail.zg - Slicinglist.slice / array.slice: 1-based and inclusive, like [i] and range[…].slicing.zg
- Slim pluginsWhat the base was slimmed into, each from the plugin this strike lists:
brain16(AI),int128and the other widths (WSMW),deci(Money), Unicode text and the case marks…slim_plugins/ · 2 files - Spelled outWritten out for the reader.spelled_out.zg
- Spread
...'xs'at a call: unpack a list into the variadic part.spread.zg - Std bareStd marks everything
bare.optional: each of std's names may be written withstd::or without it.std_bare.zg - Std op pathStd marks everything
bare.optional, so its word operators may carrystd::asstd::powhas since 2026-10-02.std_op_path.zg - Strike with buildA strike's build.zg is its build program, run by
zomp prepare, not one of its modules; the oracle skips it.strike_with_build/ · 2 files - Stringsstrings.zg
- Structsstructs.zg
- SymbolsEach spells its word's most useful general form.symbols.zg
- TestsA
test fntakes nothing and returns nothing;zomp testruns each one.testing.zg - Texttext.zg
- Text boundA length bound on text names its unit: text has three lengths.text_bound.zg
- Text to numberText → number fails
not_a_numberwhen it is not a number, andout_of_rangewhen it is one too big for the type, however many digits.text_to_number.zg - To ASCIIText into ASCII fails
not_asciiunless every character is ASCII.to_ascii.zg - To bitsThe base keeps a way to write numbers like the hardware, never the default:
to.T.bits[…]reads a value's bits as T's.to_bits.zg - Text in two forms
to.stored.str.utf8is the exact value, asprint.storedshows it;to.useful.str.utf8is the useful one, asprint.usefulshows it.to_text_forms.zg - Too big to intA whole bin or deci too big for the integer fails
out_of_range, besidenot_whole, as text that is too big does: oneotherwisehandles both.too_big_to_int.zg - Trailing commaA trailing
,is allowedtrailing_comma.zg - Two failing tasks in one blockEach handler runs where its own
concurwas written.two_tasks_fail.zg - A strike that uses anotherRicochet.zv lists it,
ricochet::dep[path = "../strikes/areas"], and itspubitems are reached with::after its own 'prefix',areas.uses_a_strike/ · 2 files - Uses bare
greetmarkshelloandNotebare.optional,waveandTonebare.only, andformal,Tallyandmergebare.never.uses_bare/ · 2 files - Uses case
shoutis case-insensitive (case.any [fn, struct, field, const];in itsstrike.zg), so this strike reaches its names in any case, with the path and bare.uses_case/ · 2 files - Variadicvariadic.zg
- WhicheverWhichever, timers, structured tasks, a task that fails.whichever.zg
- WholeBin → int fails unless the bin is whole, or
out_of_rangewhen it is whole but too big for the integer.whole.zg - Wide bitsBitwise operators and shifts on integers past 128 bits, at the type's true width: and int128/uint128 shifts and
not.bitat all 128 bits.wide_bits.zg - Integers past 128 bits
not_std.uint256and up, to LLVM's 2^23 bits.wide_integers.zg - Wide to deciA wide integer into a deci can fail
too_many_digits, whatever its value, as any integer type wider than the deci's digits can.wide_to_deci.zg - WidthsA shift's width comes from any operand whose type is known — a name, an expression, or the type it is being stored into.widths.zg
- The operators are words
plus,minus,times, and.wrapfor the wrapping ones; a negative keeps-.word_operators.zg - Wrapping arithmeticplus.wrap minus.wrap times.wrap pow.wrap are always defined — modulo the type's size — so a hash needs no no_check.wrapping.zg
- WSTN listedNames in every script, and emoji, come from the plugin WSTN, "Wanted Some Thai Names".wstn_listed/ · 2 files
- Zero everywhereNo bin or brain16 result is ever -0: a zero times a negative, a negated zero, a product too small to hold, are all plain 0.zero_everywhere.zg
- Zero quotientA whole quotient that rounds to zero is 0, never -0: 0.5 / -1.75 is -0.2857…, rounded up to 0.zero_quotient.zg