Programming in Goose

Memory-safe systems programming without a heap

Written for Goose v2026.3, October 2026

A book about Goose, a systems programming language with no heap, written for programmers who know C, Odin or Rust. Every example in it is compiled and run as part of building the book, and the output shown is the output the compiler gave.

Download

Contents

  1. Part IGetting Started

    The first five chapters cover the parts of Goose that will feel familiar if you have written C, Odin or Rust: running programs, the scalar types, control flow and functions. Goose has its own opinions even here (about integer widths, about %, about what a block evaluates to), so even the familiar chapters are worth reading closely.

  2. 1Introduction
    1. 1.1Why learn Goose?
    2. 1.2What Goose is not
    3. 1.3A first taste
    4. 1.4How to read this book
    5. 1.5About the examples
  3. 2Hello, Goose
    1. 2.1Getting the compiler
    2. 2.2The first program
    3. 2.3Two ways to run a program
    4. 2.4Checking and formatting
    5. 2.5Printing
    6. 2.6Comments
    7. 2.7When something is wrong
    8. 2.8Program arguments
    9. 2.9Exercises
  4. 3Values and Types
    1. 3.1Declaring variables
    2. 3.2Integers
    3. 3.3Floats
    4. 3.4Booleans
    5. 3.5Bitwise operators
    6. 3.6Named constants and type aliases
    7. 3.7Exercises
  5. 4Control Flow as Expressions
    1. 4.1if
    2. 4.2match
    3. 4.3Blocks are expressions too
    4. 4.4guard
    5. 4.5Loops
    6. 4.6defer
    7. 4.7Exercises
  6. 5Functions
    1. 5.1Declaring a function
    2. 5.2Reference parameters
    3. 5.3Default arguments
    4. 5.4Several results
    5. 5.5Overloading
    6. 5.6Method-call syntax
    7. 5.7Nested functions
    8. 5.8Recursion is declared
    9. 5.9Functions that never return
    10. 5.10Exercises
  7. Part IIMemory Without a Heap

    This part is the heart of the book. It explains where Goose keeps values whose size is not known at compile time, why references into them can never dangle, and how strings, arrays and structs are laid out as plain, contiguous bytes. Read it in order: each chapter builds on the one before.

  8. 6Where Values Live
    1. 6.1Three kinds of size
    2. 6.2Data stacks
    3. 6.3Leaving a scope frees everything
    4. 6.4Nothing moves
    5. 6.5Copies are visible
    6. 6.6Built in place
    7. 6.7Globals
    8. 6.8Design note: why no heap?
    9. 6.9Exercises
  9. 7The Array Family
    1. 7.1The family
    2. 7.2Fixed arrays: T[k]
    3. 7.3Frozen arrays: T[]
    4. 7.4Limited arrays: T[..k] and T[..]
    5. 7.5Grow-only arrays: T[>..]
    6. 7.6Grow-shrink arrays: T[>..<]
    7. 7.7What can go inside what
    8. 7.8Array literals
    9. 7.9Members
    10. 7.10Choosing an array
    11. 7.11Exercises
  10. 8References and Slices
    1. 8.1References
    2. 8.2Slices
    3. 8.3The one rule
    4. 8.4Liveness, not scope
    5. 8.5Writability
    6. 8.6Rebinding
    7. 8.7Exercises
  11. 9Strings Are Bytes
    1. 9.1Four kinds of string
    2. 9.2Building text
    3. 9.3Storing text
    4. 9.4Printing values inside text
    5. 9.5Cutting text up
    6. 9.6Converting to and from numbers
    7. 9.7Comparing and changing text
    8. 9.8Bytes and characters
    9. 9.9Exercises
  12. 10Structs and Inline Data
    1. 10.1Declaring and building structs
    2. 10.2Packed layout
    3. 10.3Field qualifiers
    4. 10.4Variable-size fields
    5. 10.5A growable tail
    6. 10.6Generic structs
    7. 10.7Arithmetic and equality
    8. 10.8Exercises
  13. 11Optionals
    1. 11.1A reference that may be null
    2. 11.2Narrowing
    3. 11.3Optionals as fields
    4. 11.4Optionals or a trailing bool?
    5. 11.5Exercises
  14. Part IIIModelling Data

    With the memory model in place, this part turns to shaping data: values that can be one of several kinds, structures linked together without pointers, data whose lifetimes do not follow the shape of the code, and the ways a program reports that something went wrong.

  15. 12Enums in Two Sizes
    1. 12.1Declaring enums
    2. 12.2Matching
    3. 12.3Fixed mode and variable mode
    4. 12.4Case functions
    5. 12.5Design note: why two modes?
    6. 12.6Exercises
  16. 13Links Without Pointers
    1. 13.1Self-relative links
    2. 13.2Links into a pool
    3. 13.3self: links that point back
    4. 13.4An index for a sequential array
    5. 13.5Choosing a link
    6. 13.6Exercises
  17. 14Pools for Lifetimes That Don't Nest
    1. 14.1A pool of slots
    2. 14.2Freeing frees nothing
    3. 14.3A waiting list
    4. 14.4Local pools and pool parameters
    5. 14.5Slice pools
    6. 14.6When to use a pool
    7. 14.7Exercises
  18. 15Errors
    1. 15.1Two outcomes: a trailing bool
    2. 15.2Found or not: an optional
    3. 15.3Failing from deep inside: return … from
    4. 15.4The exception module
    5. 15.5Stopping the program
    6. 15.6Choosing
    7. 15.7Exercises
  19. Part IVAbstraction and the Library

    This part covers the tools for writing code once and using it many times: generic functions, functions passed as arguments and blocks, recursion, and the standard library that is built from them. It ends with how a program is split across files and how it uses libraries written by other people.

  20. 16Generics and Blocks
    1. 16.1Generic functions
    2. 16.2Function values
    3. 16.3Trailing blocks
    4. 16.4The library's higher-order functions
    5. 16.5Nested functions as values
    6. 16.6Exercises
  21. 17Recursion
    1. 17.1The rule
    2. 17.2Pattern 1: finish with the scratch before recursing
    3. 17.3Pattern 2: pass the output in
    4. 17.4Pattern 3: a context of references
    5. 17.5Mutual recursion
    6. 17.6Design note: why recursion is marked
    7. 17.7Exercises
  22. 18A Tour of the Standard Library
    1. 18.1Importing modules
    2. 18.2std: arrays
    3. 18.3std: numbers, hashing and randomness
    4. 18.4dictionary
    5. 18.5math and vec
    6. 18.6os: files, arguments and time
    7. 18.7csv
    8. 18.8json
    9. 18.9regex
    10. 18.10The rest
    11. 18.11Exercises
  23. 19Programs, Namespaces and Packages
    1. 19.1Whole-program compilation
    2. 19.2Splitting a program into files
    3. 19.3Namespaces
    4. 19.4main and globals
    5. 19.5Packages
    6. 19.6Embedding files
    7. 19.7A program with C of its own
    8. 19.8Exercises
  24. Part VSystems Work

    The last four chapters of the language proper deal with the program's edges: running work on several threads, saving data to files and loading it back safely, calling C and being called from it, and finding and removing the costs that safety adds.

  25. 20Threads That Share Nothing
    1. 20.1A worker is a separate program
    2. 20.2Typed queues
    3. 20.3What can cross: flat values
    4. 20.4Workers that fail
    5. 20.5Design note: no shared memory
    6. 20.6Exercises
  26. 21Saving and Loading Bytes
    1. 21.1Three built-ins
    2. 21.2Verification
    3. 21.3Variable-size records
    4. 21.4What cannot be saved
    5. 21.5Writing without copying
    6. 21.6Exercises
  27. 22Talking to C
    1. 22.1extern fn
    2. 22.2What can cross
    3. 22.3A program's own C
    4. 22.4Shared libraries, bound at startup
    5. 22.5Calling Goose from C
    6. 22.6Exercises
  28. 23Performance
    1. 23.1Measure a real build
    2. 23.2Bounds checks
    3. 23.3Index types
    4. 23.4checkfree: no checks allowed
    5. 23.5Asking for inlining and vector code
    6. 23.6Data layout
    7. 23.7Design note: safe by default, fast on request
    8. 23.8Exercises
  29. Part VITwo Programs

    The chapters so far have shown each feature in a snippet of its own. This part shows two complete programs, each a page or two long, and looks at the decisions in them: where the data lives, how errors travel, and what the compiler checks. Neither is built up step by step. Each is shown whole, and then taken apart.

  30. 24A Word Counter
    1. 24.1The program
    2. 24.2One buffer, no copies
    3. 24.3Counting with update
    4. 24.4Ranking
    5. 24.5The output loop
    6. 24.6Errors and exit codes
    7. 24.7How fast is it?
    8. 24.8Exercises
  31. 25A Calculator
    1. 25.1The program
    2. 25.2One function per rule
    3. 25.3Nested functions instead of a parser object
    4. 25.4Errors from anywhere
    5. 25.5Where the data lives
    6. 25.6Limits
    7. 25.7Exercises
  32. AGoose for C, Odin and Rust Programmers
    1. A.1From C
    2. A.2From Odin
    3. A.3From Rust
  33. BLimitations
    1. B.1Limits of the design
    2. B.2Limits at the boundaries
    3. B.3Omissions of version 1
  34. CSolutions to the Exercises
    1. C.1Chapter 2: Hello, Goose
    2. C.2Chapter 3: Values and Types
    3. C.3Chapter 4: Control Flow as Expressions
    4. C.4Chapter 5: Functions
    5. C.5Chapter 6: Where Values Live
    6. C.6Chapter 7: The Array Family
    7. C.7Chapter 8: References and Slices
    8. C.8Chapter 9: Strings Are Bytes
    9. C.9Chapter 10: Structs and Inline Data
    10. C.10Chapter 11: Optionals
    11. C.11Chapter 12: Enums in Two Sizes
    12. C.12Chapter 13: Links Without Pointers
    13. C.13Chapter 14: Pools for Lifetimes That Don't Nest
    14. C.14Chapter 15: Errors
    15. C.15Chapter 16: Generics and Blocks
    16. C.16Chapter 17: Recursion
    17. C.17Chapter 18: A Tour of the Standard Library
    18. C.18Chapter 19: Programs, Namespaces and Packages
    19. C.19Chapter 20: Threads That Share Nothing
    20. C.20Chapter 21: Saving and Loading Bytes
    21. C.21Chapter 22: Talking to C
    22. C.22Chapter 23: Performance
    23. C.23Chapter 24: A Word Counter
    24. C.24Chapter 25: A Calculator

The diagrams, text and examples are original. The fonts are Lora, JetBrains Mono and Patrick Hand, under the SIL Open Font License; their licences are in fonts/.