Goose language claims to beat C++ and Rust with no heap or GC

Goose is a programming language whose project page describes it as a memory-safe systems language with no heap allocator, garbage collector or lifetime annotations. Its syntax is meant to feel familiar to C and Rust programmers, but there is no heap at all. Every dynamic value lives inline on a data stack managed by the compiler. Growth advances a pointer, and memory is freed when its scope ends. The page says the language's type and lifetime rules make this model safe.

The headline claim is about speed and memory. The page says that over sixteen benchmarks in the repository's own suite, Goose runs at 3.3x the speed of idiomatic C++, 1.16x hand-optimized C++ and 1.12x the best safe Rust, using 1.9x, 1.3x and 1.2x less memory respectively. It attributes these gains to Goose's data layouts and memory model. The figures are collective across the sixteen benchmarks and link to a separate results page.

The memory model works like this. A program has the native call stack, static data and N data stacks, where the compiler works out N. A data stack is a large address-space reservation with a bump pointer, and there is no other memory. At most one resizable value is live per stack and it is always on top, so growth never moves anything and never checks a capacity. The page says this is all proved at compile time and the runtime tracks only the bump pointers. Freeing a million-element structure is a single store, however deeply it nests. Because nothing moves, a reference into a growing array stays valid for as long as the array does. In the example, push returns a reference to the new element, and the reference to element 0 is still valid a million pushes later. The page says C++ must reserve capacity and safe Rust uses u32 indices in the corresponding benchmarks.

Safety comes without annotations. Every reference and slice has a static root, the variable that bounds its target's lifetime. The compiler infers roots, specializes functions for them and rejects references that could outlive their owners. There is no lifetime syntax, no aliasing or exclusivity rules and no unsafe. When a check fails, the error names the reference's root and its destination.

Nested data stays inline. A string, an array of strings, or a record with variable-size fields is one contiguous block with no pointer in it. The page's example is an Order record with an id, a customer name and a list of items. In Goose it takes 29 bytes and 0 allocations. As C++ std::string plus std::vector it is 160 bytes and 1 allocation, and as Rust String plus Vec it is 153 bytes and 4. The stated price: an array of variable-size elements is sequential, so you can iterate it but not index it, unless you keep a second array of references as an index.

Algebraic data types are the only dynamic polymorphism, with no inheritance or vtables. Each can be stored in fixed mode (a tag plus room for the largest payload, indexable and overwritable) or variable mode, where each value takes exactly its variant's size. In the page's example, variants take 9, 17 and 1 bytes rather than 17 each. In variable mode the array becomes sequential and a value never changes variant, but you can take references into a payload. The page claims 4x less memory and 2x the speed of a Rust enum on the one benchmark that exercises it.

Other features follow from the model. Relative references store a typed, checked link as a 1, 2 or 4-byte offset, against eight bytes for a regular T& machine address. Structures built from them are position independent, so the page's binary search tree in one grow-only array has 12-byte nodes with links included. Saving such a structure is a write; loading is a read plus a verification pass. from_bytes checks the framing, every tag, every length and every link before the bytes become a value, so a corrupt or hostile file yields false rather than a wild reference.

Values are built in place: a constructed value is written to its final destination through any depth of calls, so items.push(parse(line)) writes the parsed record straight into the array and returning a growable array by value costs nothing. An error return can leave a function any number of frames up, statically checked, with no unwinder, no Result type and no ? on every call. Threads share nothing: each worker is compiled as a separate program with its own memory, flat values cross typed queues as a memcpy, and data races, locks, atomics and memory orderings do not exist in the language. An untyped parameter is generic, and function values are compile-time entities, so a filter call compiles to the loop it looks like. Goose compiles to one C file, calls C directly through extern fn, and a bundled TinyCC backend compiles and runs a program in-process with no build step. The page links a tutorial, reference, specification, packages, standard library, benchmarks and thirty-one complete sample programs.

Key facts

  • Goose is described as a memory-safe systems language with no heap allocator, garbage collector, reference counting, destructors or lifetime annotations; all dynamic values live on compiler-managed data stacks.
  • Claimed over sixteen benchmarks in the repository's own suite: 3.3x the speed of idiomatic C++, 1.16x hand-optimized C++ and 1.12x the best safe Rust, on 1.9x, 1.3x and 1.2x less memory.
  • An example Order record takes 29 bytes and 0 allocations in Goose, versus 160 bytes and 1 allocation in C++ and 153 bytes and 4 allocations in Rust.
  • Stated trade-off: arrays of variable-size elements are sequential, so they can be iterated but not indexed unless a second array of references is kept.
  • Goose compiles to a single C file, calls C directly, and has a bundled TinyCC backend that compiles and runs a program in-process.

Why it matters

Goose goes after a trade-off most systems languages accept: C++ leaves memory safety to the programmer, while safe Rust asks for lifetime annotations and borrow rules. Goose claims safety with no annotations, no aliasing rules and no unsafe, and also claims a speed and memory edge. Its approach is to drop the heap entirely and let the compiler place everything on statically assigned data stacks, so freeing is a single store. If the numbers hold up, that is a notable design point. For now they are the project's own claims.

Who it affects

The page frames Goose for programmers who know C and Rust syntax and who care about systems-level performance and memory use. The design choices will matter most to people building data-heavy programs: nested records, parsers, trees and serialized formats, where inline layout and in-place construction are the stated source of the gains. Because Goose compiles to one C file and calls C directly, the page positions it as usable wherever a C compiler runs.

How to use it

The project page points to a tutorial, a reference, a specification, packages, samples, benchmarks and a standard library. It offers thirty-one complete sample programs. Goose compiles to a single C file, so it runs wherever a C compiler does, and it calls C through extern fn. A bundled TinyCC backend compiles and runs a program in-process with no build step.

How solid is it

The performance claims rest on the repository's own benchmarks. The speed figures are given for the sixteen benchmarks collectively, and the page links a separate results page that says losses are included. The excerpt does not describe the benchmark methodology (hardware, compilers, flags, workloads), does not list the losses, and mentions no independent verification or third-party reproduction. The excerpt names no author, maintainer or organisation behind Goose, gives no release date, version number or licence, and does not say whether the language is production-ready or stable.

Risks and caveats

The design has stated costs. Arrays of variable-size elements are sequential: you can iterate them but not index them, unless you keep a second array of references. In variable-mode enums, the array becomes sequential and a value never changes variant. The 4x memory and 2x speed advantage over a Rust enum is reported on the one benchmark that exercises it, so it should not be read as a general figure. Headline multiples such as 3.3x are measured against idiomatic C++; the gap to hand-optimized C++ (1.16x) and the best safe Rust (1.12x) is much smaller. The source text available here is truncated mid-example, so later sections of the page are not covered.

“A memory-safe systems language with no heap allocator, garbage collector, or lifetime annotations.”

— The Goose project page