news · Barcelona

Goose: a language with no heap, and references that survive growth

Goose programming language banner

Goose: a language with no heap, and references that survive growth

Wouter van Oortmerssen has been naming languages after animals since the Amiga days. Lobster was one. Goose is the new one.

Goose is a systems language with no heap allocator, no garbage collector, no reference counting and no destructors. Every dynamic value lives inline on a data stack the compiler sizes for you. Growth moves a bump pointer. Scope exit frees everything with a single store, however deeply the structure nests.

The repository went up at the end of August. It holds 1,788 stars and 68 forks today, and the latest release, v2026.3, landed on 21 October. The compiler emits one C file, so a program runs anywhere a C compiler runs, and the bundled TinyCC backend can build and run it in-process with no separate build step.

The benchmarks are his own, and the losses are in the same table. Across sixteen programs Goose runs at 3.3x idiomatic C++, 1.16x hand-optimized C++ and 1.12x the best safe Rust, on 1.9x, 1.3x and 1.2x less memory. Those numbers come from data layout more than from clever codegen.

The part worth sitting with is not the speed. Arrays grow in place, so a reference into a growing array stays valid for as long as the array does. Push a million elements after taking that reference and it still points at element zero. C++ makes you reserve ahead. Safe Rust hands you a u32 index instead of a pointer. Goose keeps the typed reference.

That one decision cascades through everything else. Records hold their variable-size fields inline, so an order that costs 160 bytes and one allocation as a C++ string plus vector costs 29 bytes and no allocation here. Enums in variable mode take exactly their own variant's size rather than the largest one's. Relative references store a typed, checked link as a one, two or four byte offset, which makes a structure position independent and therefore already its own file format. Saving is a write. Loading is a read plus a verification pass that rejects hostile bytes before they become values.

The costs are documented honestly in section 18 of the tutorial. Arrays of variable-size elements iterate but do not index. A recursive function cannot hold growable data across its own call. No escaping closures, no function pointers, no dynamic dispatch past ADT tags, and whole-program compilation only.

Eighteen public repositories on the account. Amiga E came before most people reading this were writing code. A language this opinionated is worth one afternoon, whether or not you ever ship anything in it.

Repo and releases: https://github.com/aardappel/goose

■ Filed from The Foundry: the Fern, Fire wing of the city.