deniz.in

Markets

Weather

Loading weather

· via Hacker News – Front Page (native)

Goose language claims to beat C++ and safe Rust with a heap-free memory model

A new systems language called Goose replaces the heap with compiler-managed data stacks, and reports benchmark wins over hand-optimized C++ and safe Rust while enforcing memory safety with no annotations.

Goose language claims to beat C++ and safe Rust with a heap-free memory model

A new systems language named Goose claims to beat C++ and safe Rust at their own game: faster, smaller, and memory safe, with no allocator, no garbage collector, no reference counting, and no lifetime annotations. The project, hosted on GitHub under the account aardappel, reached the Hacker News front page this month on the strength of one unusual premise: there is no heap.

The claims

According to the project's README, across sixteen benchmarks Goose runs at 3.3x the speed of idiomatic C++, 1.16x the speed of hand-optimized C++, and 1.12x the speed of the best safe Rust code, while using 1.9x, 1.3x, and 1.2x less memory respectively. The README argues the gains are structural, coming from properties of the language itself rather than tuning, and links a full results page that it says includes the benchmarks Goose loses.

One memory model: data stacks

A Goose program has the native call stack, static data, and a compiler-determined number of data stacks. Each data stack is a big reserved address range with a bump pointer, and no other kind of memory exists. At most one resizable value is live per stack, and it always sits on top, so growing a value never moves existing data and never checks capacity. All of this is proved at compile time; the runtime tracks nothing but the bump pointers. Freeing is a single store at scope exit, so releasing a million-element nested structure costs the same one store no matter how deep it goes.

Because values never move, a reference into a growing array stays valid for as long as the array does. Pushing an element returns a reference to what was just created, and the README credits this property — which C++ vectors and Rust's Vec cannot guarantee because they reallocate — with a significant portion of the benchmark wins.

Safety with no syntax

Memory safety rests on one rule: a reference must not outlive the variable that owns its target, and must never view that target at the wrong type. Every reference carries an inferred static root naming its owner, and functions are specialized per root. The upshot, per the README, is safety with no lifetime syntax, no aliasing or exclusivity rules, and no unsafe escape hatch. When the checker rejects code, it names both ends of the conflicting lifetime.

Flat data, cheap enums, offset links

Strings are u8 arrays, and structs may contain variable-size fields stored inline, so composite values are single contiguous blocks with no internal pointers. The README gives an example order record that occupies 29 bytes with zero allocations in Goose, versus 160 bytes and one allocation with C++ std::string and std::vector, and 153 bytes with four allocations with Rust's String and Vec. The trade-off is that arrays of variable-size elements are sequential: they can be iterated but not randomly indexed.

Enums are the language's only dynamic polymorphism — there is no inheritance and no vtables — and each can be stored two ways. Fixed mode reserves room for the largest payload; variable mode gives each value exactly its own variant's size. On the benchmark exercising this, the README reports 4x less memory and 2x the speed of a Rust enum.

References between objects can also be stored as relative offsets of one, two, or four bytes. Structures built this way are position independent, so a saved data structure is effectively its own file format: saving is a write, and loading is a read followed by a verification pass that rejects hostile bytes.

The rest of the package

Errors return through any number of stack frames via a statically checked return err, with no unwinder, no Result type, and no question-mark operators on every call. Threads share nothing: each worker is compiled as a separate program with its own memory, and values cross typed queues as a memcpy, which removes locks, atomics, memory orderings, and data races from the language entirely. Values are constructed in place at their final destination through any depth of calls, so returning a growable array by value is free. Generics are expressed as untyped parameters, and function values are compile-time entities that compile down to plain loops.

Goose itself compiles to a single C file, so it can run on any platform a C compiler targets and call C directly through extern fn. A bundled TinyCC backend compiles and runs a program in-process, with no separate build step.

Why it matters

The received wisdom in systems programming is that memory safety carries a cost: a garbage collector, lifetime annotations, runtime checks, or disciplined manual management. Goose's wager is that deleting the heap deletes the cost — along with the annotation burden, the invalidation bugs that come with reallocation, and the serialization step — all at once. The performance claims come from the project's own benchmark suite, and cross-language benchmarks are famously contestable, but the README is at least candid that some results go against it. As an artifact the language may remain niche; as a set of ideas — bump-pointer data stacks, pointer-free flat layouts, offset-based links, checked multi-frame error returns — it challenges the assumption that C++ and Rust already occupy the entire performance-and-safety design space.

  • #programming-languages
  • #memory-safety
  • #systems-programming
  • #benchmarks
  • #compilers