The Goose Programming Language

361 points - yesterday at 7:06 PM

Source

Comments

Aardappel yesterday at 7:55 PM
Btw I made the language, AMA. repo: https://github.com/aardappel/goose
malisper yesterday at 8:42 PM
I'm curious, for someone more familiar with Goose: how do you represent an arbitrary number of dynamically sized values? If you have a fixed number of stacks, it seems like only a fixed number of values can change size at any given time.

For instance, how would you represent a hash table where the values are strings and at random, the program inserts or deletes a random string?

This doesn't seem like something you could easily represent. The only way I can think of is to keep a stack that holds all of your strings, and you periodically compact it.

Edit: Maybe you could also have a separate stack for strings of various sizes. One each for strings less than 8, 16, ... bytes. But at that point you're basically implementing your own malloc by hand.

Edit: Fwiw I do think Goose is very cool! I've had to hand-roll a lot of similar stuff in Rust before to speed up memory management

malkia yesterday at 11:07 PM
"Threads that share nothing. A worker is compiled as a separate program with its own memory, and flat values cross typed queues as a memcpy. Data races, locks, atomics and memory orderings do not exist in the language."

That reminds me of Dart Isolates - https://dart.dev/language/isolates

ebiederm yesterday at 8:29 PM
I seem to remember the ML guys went down this route. I believe they called it regions.

From what little I read in the literature I seem to recall that there were enough programs with quite a bit more memory usage that they decided this approach was a dead end.

Does anyone know anymore details?

pradn yesterday at 9:25 PM
Goose is pretty cool. The idea is that you don’t need to make representable all programs: a language for a restricted purpose is ok. As long as you can statically specify the number of growable memory regions, you can use Goose. However, since there’s no garbage collection, you’ll probably need to be careful about memory use while a program is running. Ie: the stacks can get too big if you keep growing them, even as old data is not used any more.

Still, for a large number of programs - like data-oriented applications - it’s probably a good fit. It might work ok with entity-component game systems as long as you reuse old memory…

anigbrowl yesterday at 8:35 PM
This looks very interesting! I mostly write in garbage-collected languages (to the extent that I still write anything by hand...) so I'm just a spectator in memory management debates, but it's often struck me that heap management is more of an art than a science. The idea of treating memory more like stacks made immediate intuitive sense to me. I'm also fascinated by the thread implementation, although I'm not knowledgeable enough to to think through the potential benefits/costs vs other approaches to concurrency.

I wonder if the name of the language was inspired by the way geese fly in formation, with trailing birds saving energy by flying inside the aerodynamic shadow of the leaders, and swapping in and out as needed. If so, a very nice metaphor for the memory management model.

I was also impressed by the documentation. As we know AI-generted docs tends to be rather mediocre, but the author has clearly invested time in making in readable such that the relevance and rationale of design decisions provide the context that a curious programmer needs to understand why things are implemented in a particular way.

I really appreciated the detailed samples, ranging from simple algorithmic theorems up to a small game. Again, I don't have the experience to rate the language vs others, but I was struck by readable the code was and how easy it was to follow task flow. Not having to think about classes is always a plus!

Anyway, I usually the the offering of a new language with dispassionate interest, as something to be aware of and but not get too invested in or familiar with until it gains enough popularity to have a good shot at longevity. Goose is the first language in a long time where I looked at it and immediately thought that I'd like to use it for its own sake.

bobbydigitales yesterday at 7:32 PM
"That looks really neat! The automatic analysis and use of multiple data stacks and resizable fields takes it from "lots of work can be done this way" to "basically everything can be".

The relative references and built in binary structure validation also enable direct memory mapping of data structures and immediate use of network data. "Parsing" file and network data is often 100x slower than it needs to be." - John Carmack

pulse7 yesterday at 8:03 PM
Educate me: how to create a program in Goose which reads a JSON structure, prints it out and finishes. How is memory for JSON allocated on stack? It can be from 1K to 1M - depending on the file...
Aardappel yesterday at 9:07 PM
I made the language, AMA :)
hbogert today at 7:29 AM
mighty interesting, i scanned the nuances about the memory model, but it doesn't explicitly say so, but am I right that some workloads will result in heavy fragmented physical memory allocations?
weinzierl yesterday at 8:05 PM
Rust's appeal (to me) is safety, performance, DX in that order.

Where does Goose sit when classified along these dimensions?

Sure, performance is right there on the packaging but no word about UB in the README. I read "Goose has syntax familiar to C and Rust" as DX in the same ballpark, but is it a performance first or safety first language.

If it is the former it occupies the same crowded niche as C++ and its many cousins and will have a hard time.

If it's the latter it will have much more room to prosper. We don't have enough languages in the niche that Rust and Ada fill right now.

baud9600 today at 4:11 AM
Great work on Goose, a whole load of practical thought went into it!

I’d love to see 1st class lightweight ‘processes’ and typed comms, like CSP. These light processes would be cheap to spawn in the thousands, with synchronous comms. So it’s possible to quickly use arbitrary networks rather than OS thread worker pools with queues. Maybe like:

fn produce(out: chan<i32>) { for i in 1000 { send(out, i); } }

fn consume(inp: chan<i32>) { for i in 1000 { print(recv(inp)); } }

fn main() { let c = chan<i32>();

  par {
    produce(c);
    consume(c);
  }
}
AnEro yesterday at 7:50 PM
Such a cool idea! I've been toying around making a few libraries to force languages to do that direct io zero-read mapping to data structures. Ofcourse this looks way better and infinity less hacky, but it is a fun and trippy experience to find someone working in the same direction as you independently.
malkia today at 12:30 AM
How would this work in wasm land? It's a bit badly put question, because this leaves out a lot of context - wasm - where, how, what implementation, but from my simple understanding most of the wasm is 32-bit running in a browser. For this to work, it'll need true virtual 64-bit (or 48-bit) address space. The host, being the browser, or something else, may provide it, but....

If the host needs to load several of these .wasm, compiled with goose, then it'll have to run them in separate (browser) instances too (or maybe that's how wasm works by default - not sure).

It just got me thinking - the languge is prepared to translate into javascript workers, because it's really single threaded by nature with communication between threads (or put in the dart languages term "isolates"), which makes them perfect for the browser, now the only question is the memory layout.

malkia today at 12:26 AM
For Windows, these N data stacks would probably just RESERVE the address space, and as it grows COMMIT it, right?

I guess there would be some penalty to be paid here for smaller pages, but being mostly contigous might also help some.

That to be said, such language seems to require 64-bit virtual address space in order to function reasonably, right?

Also a .dll written in it might not be the best suited, for example if loaded in the middle of fragmented virtual address space it may need to find itself hard to allocate N contigious data stacks (do they absolutely have to be contiguous, what if they are simply ropes or deques or connected chunks ... obviously if some data structure requires to be contigous that would be a problem, but maybe this can be expressed somehow.... or maybe I'm overthinking here).

Super excited about this!

kadw yesterday at 9:12 PM
It would be really great to see how it fits in embedded systems, MCUs in particular!

Embassy (https://github.com/embassy-rs/embassy) uses this concept of no heap allocation and I find it really solid. Even if you write in C, most of the times you don't use heap. MISRA, the C coding standard for automotives, doesn't allow dynamic allocation!

deleted today at 4:02 AM
wewewedxfgdf yesterday at 11:21 PM
What are the down sides? That's the key question when a better thing comes along.
andsoitis yesterday at 8:04 PM
Lobster is the author's other programming language, previously discussed on HN: https://news.ycombinator.com/item?id=47239955
daoxid yesterday at 8:50 PM
I'm curious, when returning a dynamically sized array from a function, does the whole array need to be copied? C++/Rust would simple move the array out of the function (i.e., they would only copy the pointer to the underlying data), but it seems this wouldn't work in Goose if the stack the dynamic array lives in is cleared on return?
deleted yesterday at 8:16 PM
asinglesprinkle today at 3:09 AM
Im not gonna judge it by anything other than name. Its awesome, Goose it up.
Panzerschrek today at 5:02 AM
> Memory is a handful of data stacks that the compiler assigns statically

I doubt this can work well in all cases. Sooner or later one needs proper heap.

deleted yesterday at 9:28 PM
cardanome yesterday at 11:58 PM
I hate when I see a new programming language, get my hopes up and it turns out to be AI slop again.

There might be some decent design ideas there but if you can't be arsed to write them down in your own words but instead make me read AI generated slop I am out.

pron yesterday at 8:46 PM
Interesting, but can you write something like an LRU cache?
FrankWilhoit yesterday at 8:34 PM
The right ideas. Not optimized for reallocation. Creates pressure to overload types, making secure software unattainable.
calvinmorrison yesterday at 10:16 PM
Can someone explain the weird phrasing here "Nothing moves, so references survive growth" that AI does.
timcobb yesterday at 8:46 PM
> One memory model: stacks, and scope exit is the free

What are the ergonomics of this I wonder.

nnevatie today at 7:00 AM
> and scope exit is the free

And doc is the slop.

groundzeros2015 yesterday at 9:41 PM
He didn’t comment on goose. He talked about a concept and the goose guy said “that’s like my idea”. And John said “yeah sounds like it”.
skrebbel yesterday at 8:48 PM
I love that the logo is a very fast goose
cartothug today at 1:36 AM
God the AI slop writing is horrible. Please just write the docs yourself, as others have stated, I can’t trust this at all. The “the one idea” made me cringe so hard I almost fell out of my seat. Every time I make something that’s exactly what Claude writes for the starting page.
alfiedotwtf today at 3:39 AM
I remember Intel’s segmented memory model, and in the end everyone just wanted a single large and flat segment
gigatexal yesterday at 9:11 PM
Would be interesting to see Luke’s Zed language from the replies on HN.
baalimago yesterday at 8:09 PM
Do android dream of goose?
rvz yesterday at 8:43 PM
If you can't be bothered to read and structure your own README after getting an AI agent to write more than 10,000+ lines on a single page, it becomes a DONTREADME.md.

Yet, the author expects YOU to read all of what they didn't write. So I ain't reading all of that.

rfgplk yesterday at 8:29 PM
Keep going, and I hope more people start rolling their own languages.

If anyone is interested, I'm fairly close to finalizing Slang and I'm considering open-sourcing it in the near future. What originally started as a simple register based lang for an embeddable VM turned into an insanely expressive meta?programming language. Full system Fω, expansive whole program reflection (you can reflect on absolutely anything), string memory & logic safety..

You can do stuff like this:

   (fn answer () -> i64 0)
   (defpass build-answer
     (phase source)
     (transform (lambda (f)
       (fn-with f 'body '(let ((a (arr (42)))) (at a 0)))))
     (safety (lambda (goal) (syntax (refl)))))
   (run-pass build-answer answer)
   (fnmut answer
     (transform (lambda (f)
       (if (memory-safe? (check-memory (current-program)))
         f (syntax-error 'unproved-memory)))))
   (defpass inspect-ssa
     (phase ssa)
     (transform (lambda (f)
       (if (memory-safe? (check-memory (ssa-current-program)))
         f (syntax-error 'unproved-ssa-memory))))
     (proof (lambda (goal) (syntax (refl)))))
   (run-pass inspect-ssa answer)
   (answer)
or this:

   (fn next ((i i64)) -> i64 (+ i 1))
   (fncontract next
     (ensures result (successor (Eq i64 result (+ (old i) 1)) auto)))
   (fn read-second ((i i64)) -> i64
     (let ((a (arr (0 42)))) (at a i)))
   (fncontract read-second (requires (one (Eq i64 i 1))))
   (let ((i (next 0)))
     (with-proof ((one (Eq i64 i 1) (result-proof i successor)))
       (print (read-second i))))
it also supports full inline asm or llvm ir:

   (var answer 0)
   (asm (input rdi 20)
        (input rsi 22)
        (output rax answer)
        (mov rdi rax)
        (add rsi rax))
   (print answer)

   (macroop \ (a) (asm (mov a rax)))
   (\ 42)

   (print (llvm add 20 22))
   (print (->i64 (llvm fused-multiply-add (f64) 6.0 7.0 0.0)))
   (llvm fn sum32 ((x i32) (y i32)) -> i32
     (block entry
       (value answer (llvm add x y (declare (flags nsw))))
       (llvm return answer)))
   (print (->i64 (sum32 (the i32 20) (the i32 22))))

Even though you can write this by hand, the core idea is to get a very dense and terse language that LLMs can emit while guaranteeing safety and performance.
deleted yesterday at 8:09 PM
deleted yesterday at 8:09 PM
iacuobos yesterday at 8:01 PM
I can't see a reason to use this and not C++ It reads like slop text
IshKebab yesterday at 8:28 PM
PLEASE rewrite this without AI-isms. AI can write perfectly good code now, but its prose - even the latest models - is just awful to read. It hurts my brain to read this.
FrustratedMonky yesterday at 8:02 PM
Looks cool, and well developed. But really, cover pages need some better TL;DR, about the purpose. What is it for? There are a ton of languages out there. What gap is this filling? What is the purpose, the use case. Why do I need to keep reading further?

Edit Man, two posting about Goose back to back. Carmack alone might be enough to read further.

https://news.ycombinator.com/item?id=50224100

anonymous908213 yesterday at 8:34 PM
[flagged]
joshsyn today at 3:41 AM
[dead]
ethanhood_okroh yesterday at 9:04 PM
[flagged]
mi_lk yesterday at 7:40 PM
Obviously the guy is replying to something that you can't see without logging in twitter. And without context this means little
spying_lg_tv today at 12:08 AM
[dead]
mihaaly yesterday at 8:34 PM
Oh, is this then the Holy Grail of memory handling or what?!

Please share it with logistics guys, since putting stuff from here and there into warehouse storage, then taking away, put some more in than planned sometimes, keeps spinning their heads. They need all the good logic!

So, yet another programming language, that's nice. I never thought there will be one more beyond English.

  Evolution of programming languages:
  - 1940s → Machine Code ( 0s 1s )
  - 1949  → Assembly
  - 1957  → FORTRAN
  - 1959  → COBOL
  - 1964  → BASIC
  - 1970  → Pascal
  - 1972  → C
  - 1983  → C++
  - 1991  → Python
  - 1993  → Ruby
  - 1995  → Java
  - 1995  → JavaScript
  - 1995  → PHP
  - 2000  → C#
  - 2009  → Go
  - 2010  → Rust
  - 2011  → Kotlin
  - 2011  → Elixir
  - 2012  → TypeScript
  - 2014  → Swift
  - 2015  → Solidity
  - 2026  → English
geoffbp yesterday at 7:56 PM
No relation to https://goose-docs.ai/ I guess?