Getting Started
OverviewLanguage GuideFull Reference
Book
Table of ContentsIntroductionPrefaceGetting StartedLanguage TourOwnershipErrorsConcurrencyStdlibNetworkingDataPackagesSpeed & SafetyCross-PlatformToolingCookbookAppendix
Reference
Standard LibraryKeywordsPerformanceSecurityBuilt-in FunctionsStatusDebuggingABI
How-To
Getting StartedHTTP APIsErrorsPackagesConcurrencyMemoryWASITestingRelease Builds
Project
RoadmapVisionChangelogContributing

Language Overview

Mako language

Mako is a systems and backend language: clear to write, strict at compile time, fast at runtime, and designed so builds stay fast.

Product version: 0.2.1 (mako versionmako0.2.1).

Guided tour: The Mako Book.
Current syntax guide: GUIDE.md. Low ceremony: ERGONOMICS.md.
Identity (our syntax): IDENTITY.md.
Keywords: KEYWORDS.md.
Product north star: VISION.md.
Honest matrix: STATUS.md.
Changelog: ../CHANGELOG.md.


Design pillars

Pillar How
Clear Concise keywords, braces, local inference
Strict Static types, no null, exhaustive match, Result / Option
Fast binaries Native code via C (today)
Fast builds Linear frontend; debug -O0 by default
Speed As close to Rust as possible — no GC, native -O3 -flto (SPEED.md)
Concurrent (first-class) crew / kick / join / channels / select / actor — structured, no orphans
Parallel (first-class) fan — data-parallel map over cores; multi-kick crews
Memory hold / share / arenano GC
Safe by default Bounds checks; unused Result is an error

Syntax identity — ours

Mako is a unique language with unique syntax.
Not a Go dialect. Not a Rust dialect. Not a hybrid costume of either.

// Mako — preferred
fn handle(req: Request) -> Result[int, string] {
    hold let body = req.body
    arena a {
        let msg = arena_text(a, body)
        crew t {
            let j = t.kick(process(msg))
            return Ok(j.join())
        }
    }
}

on Point {
    fn distance(self) -> int {
        return self.x + self.y
    }
}
Mako-native (preferred) Dual / compat sugar
fn func
let / let mut := / var
x: int x int
-> int bare int after )
on Point { … } func (p Point) …
struct Point type Point struct
export Capitalized names
crew / kick / join (no free go)
hold / share / arena

Rule: docs, book, and mako fmt lead with the left column.
Dual forms stay for familiarity and migration — they do not define the brand.

Full identity checklist + %: IDENTITY.md (~86%).
Optional dual-form inventory: GO_SYNTAX_CHECKLIST.md.


Generics (0.2.1)

User type parameters on functions, structs, and enums. All instantiations are monomorphized (one concrete C shape per args).

fn id[T](x: T) -> T { return x }

struct Pair[T] { a: T, b: T }
enum Box[T] { Val(T), Nothing }

fn describe_all[T: Describable](x: T) -> string {
    return x.describe()
}

fn main() {
    let p = Pair[int] { a: 1, b: 2 }
    let q = id(p)
}
Topic Status
Generic functions Done (also dual fn f<T>(…))
Generic structs / enums Done — write Pair[int] { … }
Nested monomorphs Done — e.g. Box[Pair[int]]
Interface bounds T: I Done — structural method set
Iterator for via next Seed — by-value self does not auto-advance
Mutable lambda captures Seed — heap cell when body assigns outer locals

Full grammar: LANGUAGE_SPEC.md · tour: GUIDE.md §6 · book: ch03.

Operators

= is assignment only. Comparisons: == != < > <= >=.
Logical: && || ! (and and / or / not).
Bitwise: & | ^ &^ << >>, unary ^.
== / != work on strings (by content), named structs (field-wise), and enums (tag + payload).

Strings

Byte strings with length. Prefer region ops when you only need to compare or search a span — no substring allocation:

Builtin Role
str_eq / str_contains / str_index whole-string
str_slice_eq / str_slice_ci_eq / str_slice_contains / str_slice_index s[off:off+len] without alloc
str_at_eq / str_byte_at prefix-at-offset · single byte

See BUILTINS.md § Strings and examples/testing/str_slice_zc_test.mko.

Comptime (const / const fn)

Integer const bindings and const fn bodies fold at compile time:

const fn clamp(x: int, lo: int, hi: int) -> int {
    if x < lo { return lo } else {
        if x > hi { return hi } else { return x }
    }
}
const N = clamp(50, 0, 10)  // 10

Supported in const: + - * / % bitwise, comparisons, && || !, let / assign, return, if/else, if-expressions, match on ints (|, _, bind), bounded while / for, C-style for, bare break / continue, string seeds (const S = "…", +, str_len / ==), and const fn string params/returns (plus int fns that use string locals). Not a full CTFE interpreter.

Actors

actor Counter {
    n: int = 0
    receive Inc { self.n = self.n + 1 }           // tag only
    receive Add(delta) { self.n = self.n + delta } // int payload seed
    receive Bye { let _ = 0 }
}
// Counter_spawn() · Counter_send(m, Counter_Add(5)) · Counter_loop(m)

Desugars to mailbox helpers; messages pack tag + optional int payload (actor_pack / actor_msg_tag / actor_msg_payload). Bye/Stop stops the loop. Tests: actor_test.mko.

Interfaces

interface Adder { fn add(int) -> int }
on Counter : Adder {
    fn add(self, delta: int) -> int { return self.n + delta }
}
fn use(a: Adder, d: int) -> int { return a.add(d) }

Dyn values use a fat pointer + vtable. Also free-fn form Adder_Counter_add. Tests: iface_*_test.mko, iface_on_iface_test.mko.

Collections (maps & slices)

One monomorphized surface — no special collection package for everyday work. Codegen emits only the map monomorphs used in the unit (demand-driven), so large packs stay O(used shapes), not O(types²).

Form Notes
[]T int/string/float/bool/byte/Struct/Enum; nested [][]T; bag slices []Option / []Result
map[K]V K: int|string|float|bool|Struct|Enum · V: same, []T/[][]T, nested maps (depth ≤3), bags Option/Result (incl. nests), tuples (T,U[,…]) (incl. bag/chan fields), chan[T]
Ops m[k], m[k]=v, has, delete, len, comma-ok, range, maps_*

Short patterns (sets, groups, nested maps, bag values): ERGONOMICS.md.
Hands-on: howto/10-collections.md · book ch03.
Full guide: GUIDE.md §4b–4c · builtins: BUILTINS.md.

Packs & pulls

Always pack-qualified (clear call sites). Default name from optional pack clause or path basename. Prefer as for aliases.

pull "strings"
pull "./lib.mko"                // → lib.* if pack lib / path lib
pull "./util.mko" as helper     // alias
pull _ "fmt"                    // blank: load only
pull . "./helpers.mko"          // specialized: bare names
pull (
    "path"
    "fmt"
)
// dual: import / package still parse

// Types are pack-qualified too (same surface as calls):
//   fn use(t: eng.Table) -> eng.Table
//   let t = eng.Table { n: 0 }
//   match t { eng.Table { n } => … }
// Enums: eng.Red / eng.Green(n) / eng.Color.Red / eng.Color.Green(n)
// Multi-return of pack structs: let t, n = eng.grow_pair(t0, 1)
// Maps: keys int|string|float|bool|Struct|Enum
//   values: same | []T | map[K2]V (depth 2) — any combo
//   e.g. map[string][]int, map[Point]int, map[Color][]string,
//        map[string]map[string]int, map[string]bool
// Nested slices: [][]T (make / append / index / range)

Concurrency & parallelism (first-class)

Speed is the game; concurrent and parallel work is in the language, not a package:

// Concurrent — structured crew
crew t {
    let j = t.kick(work())
    print(j.join())
}

// Parallel — fan across cores
let out = fan items, fn(x) { heavy(x) }

Ordinary kicked jobs are joined with the crew. A blocked C/FFI call can delay that join. An explicit detach must be paired with detached_join_all(). No async coloring. Details: SPEED.md.

Memory

Tool Role
Scope / let Default
arena Request/batch bulk free
hold Unique / move
share Shared read (RC seed)

Errors

No null. Use Option[T] and Result[T, E]. Propagate with ?.
Discarding a Result is a compile error unless let _ = ….

GUIDE.md · IDENTITY.md · COMPAT.md · SECURITY.md · VISION.md

Edit this page on GitHub Report an issue