I would throw the entire docs out and write it from scratch in your own words. I get that we live in an era where the machine writes most/all of the code, and I can accept that. What I need, to even consider using and extending this project, is some understanding of what part of the design is yours and what part is accident by Claude. I can't get that from reading Claudese.
>>I get that we live in an era where the machine writes most/all of the code
Only on the Internet is this true, not in real life. I cannot and do not trust any of these things to do a proper job because they have not in any situation succeeded in any job I've given them. And no company I deal with claims otherwise
Right I feel like they just got to a point where they can reliably write individual functions with direction. Every time I've tried to use them consistently I feel like I just end up spinning wheels from them doing things that mostly work until it crashes and burns or just has straight up missing things or half truths. Skill issue or not it doesn't work for me.
Still glad I basically never have to debug a build issue or memory error again though
If the Code is bad, you can tell it to fix it to match your expectations —only at the edges, are you going to have to spell it out.
Lack of documentation used to be a running joke.
The goose_spec.txt in 2019 would be "goose is like c and rust only with syntax like array{;}[] btw it uses a small amount of stacks instead of malloc."0 10klocs.
Now, we make sure the AI leaves documentation so it can figure out what it was doing earlier.
A local model a few generations and many weights behind newest Claude can implement my novel algorithms and write the documentation I wouldn't.
Yes, many times it does dumb CS for kindergarten mistakes but it only has to work towards the optimum every once in a while.
Eh, I think the tutorial is pretty readable? It's concise enough.
With the tutorial, the summary also makes more sense. I have not read the other parts yet, but so far I like what I see.
All is in pretty good taste, and I like what I've seen so far. I do not care if the author himself came up with the idea, or if AI came up with it and the author approved.
I do not understand why you "have to" know this to make use of it. You can judge ideas independently of where they came from (and you should).
The version of the documentation which I would very much like to see would be a Literate Programming version where all the code is explained from the ground up.
Once a week, I tell Antigravity (3.8-flash) to rewrite every code comment and documentation that was changed in the past week. Neither GPT nor Claude can write like a human.
We as a society have to cut this low effort commenting out. The documentation is perfectly comprehensible. What action would you take differently if a given feature were implemented by Claude, or a human?
If you've ever been tasked with coming up to speed on a system mostly documented with AI writing, you'll quickly realise how hard it is to trust anything you are reading. Even if the Claude documentation is 100% accurate, you'll never shake the worry that some crucial fact you founded your understanding on was wrong. It's a fast recipe for psychosis.
That's without even mentioning that AI writing can often state the what but not the why. That human perspective is usually the most valuable knowledge to get across in writing.
As I said in my message, it would determine whether I use the project or not. I need to match it to my use cases, and if I find a match I need to know: is it matching because my use case falls in the domain of what the human collaborator wants from this project, or is my use case a hallucination that will go unsupported?
You cannot tell either from the AI written docs. I'd rather OP gave a rambling post about some problem he has in gamedev that led him to think a new language was needed, why the constraints are different, and how this will improve X, Y, or Z in his own words. Then I can infer what this project is and where it is going. Right now, I have no clue.
Comprehensibility does not equal correctness or fitness. As if that wasn't enough, or perhaps in most related manner, an LLM/AI cannot be held responsible for what it produces, by nature, especially considering the fact that a _human_ claims all of it as their own work, or at least take responsibility. Meaning that when a parable of documentation is discovered to be bogus, you can't pin it on AI, you go to the human and ask them why the documentation is wrong, and it's not a good look.
For a programming language? It's subpar and you know it.
See this for a language docs site by a small-ish team, but a significant effort was put into making it nice to read: https://tour.gleam.run/everything/
I find your comment much much lower effort than GP you took a snip at. It's true that more ppl may align in your thinking, but dissing the other side's concern as low effort does not belong in hn.
Oh wow this takes me back. We had very poor internet connectivity when I was growing up, so my brother and I played Sauerbraten and a handful of other games exhaustively with a crossover cable strung between our rooms.
> Nested data stays inline. A string, an array of strings, a record with variable-size fields and an array of those records are each one contiguous block with no pointer in it. A record that is 160 bytes and an allocation in C++ is 29 bytes and none in Goose.
It means that to do variable sized things like vectors and strings, C++ often ends up having to allocate their contents dynamically. Which results in data structures with lots of 64-bit pointers over multiple allocations.
Even Rust's "enum" feature, which can store different sized things all in the same space, does that at the cost of the smallest variant being just as big as the biggest.
Goose can do all of that not only inline (no pointers), but with variable size, meaning small items take less space. It's like a serialized data representation, but iterable. It makes for big space savings vs these languages.
As far as I can tell, you're essentially creating a new stack for every dynamically-sized variable (because otherwise nothing would be able to grow by bump allocation without moving). But this means you're creating a separate virtual memory allocation for each of these objects, which (I presume?) then rounds the size up to the OS's minimum page size (4KiB or similar).
Doesn't that waste a lot of space? Or is there something I'm missing?
Also it would seem to force every allocation to go through the OS kernel to allocate unless there's some trick to avoid that.
I wish it was more clear about the memory layout of nested variable sized data structures. As far as I can work out the max capacity is decided at construction time which makes the whole thing a lot less intriguing.
> 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.
how to perform this copy without atomics?
do the workers run as threads or processes?
also you claim it's faster than rust and c++. but for certain kinds of software it's certainly (and substantially) slower, right?
The copy is made by the runtime, which obviously does use atomics underneath, but you don't ever use these yourself.
The workers are threads. The separate memory is the concurrency model, but it's still single process, multiple threads.
The "faster than" is on average, and both in my own benchmarks and independent benchmarks you can find examples of algorithms where it is slower, but they tend to be the exception. "substantially" slower I haven't found yet.
> The "faster than" is on average, and both in my own benchmarks and independent benchmarks you can find examples of algorithms where it is slower, but they tend to be the exception. "substantially" slower I haven't found yet.
Well message passing with literal memcpys (rather than, say, just a shared buffer, like is common in Rust) is very expensive when the messages are huge. Of course as the message size increases, the Rust program will become faster than the Goose one (and if it doesn't, you should look into your benchmarks)
Being more specific, it means that for each message, we are writing on memory twice - one to build our own buffer with the message, and another to make a copy to another worker. Message passing violates, in spirit, the Goose rule that things are built on their end destination: we can't write into a buffer owned by another task, so we need to first write on our own buffer, and then do a copy, which is a lot like first writing the value to the stack, then copying the heap. Writing twice has an overhead, specially when messages don't fit in the cache - you just need benchmarks with sufficiently large messages to demonstrate it.
Beyond that, there are some algorithms that can be made much faster when written with atomics rather than message passing. (Also there are algorithms that will get faster if you use locks! Locks aren't always slower). It's just a matter of finding such examples, and writing a Rust code that will use atomics, compared to a Goose program that uses messages between workers because Goose doesn't expose atomics to the user.
So if you didn't find such examples, it's because you didn't specifically write benchmarks with those scenarios in mind (or, I mean, didn't told your LLM to write this).
That is: if the Rust program and the Goose program do the same thing in the same way, then it's reasonable that Goose is faster on average. But Goose is limited because it doesn't let you do some things, but Rust does, so to compare the languages you need to find those cases where the Goose limitations end up making the software slower
I have my own language I'm working on in private and it's nice to see other people coming to the same conclusion on region based memory. I was heavily influenced 7 years ago from learning from HandmadeHero and the community around it, and so I made that memory model one of my goals from the start, and it is indeed possible to get very fast programming with it when you make it your default, and when you make the language able to statically analyze it more.
That is about where our similarities end, though, since I'm doing quite a lot of other stuff in the midst as well (much heavier type stuff, fully incremental, retargetable, reflection, integer range tracking, blah blah blah), and the more goals you have, the complexity blows up exponentially. I do think that the region based memory part alone is worthwhile to have as a language feature, so I applaud your pragmatism. I like your syntax for returning through call stacks, too.
There are other languages that do this, though. Did you look into any of the others? Or ones like Odin which give you the configurable bump allocators and scratch space as well? Mainly I'm curious about your opinions of prior art.
anyway, hope this project goes well! the secret of the arena allocator seems to be out now to the mainstream. I think this is also a strength of array programming languages in the tradition of APL/J/K/Q.
As this project develops, I'll get to benefit from your public crowd sourced testing and design before having to publicize mine :P
I will take a better look at Goose some time later when it's not late at night.
Just wanted to drop by and thank you for creating Treesheets. I haven't given its more advanced features the use they deserve, but I love it as a note-taking application for anything that complexity-wise sits between a short outline in a plain text file and a ton of Markdown in something more advanced like Obsidian. And for, of course, any tabular data.
Good question, not sure without testing. Likely it will still give the error. It could elide it, but I am not sure how useful that is.
Optimized builds go thru the local C compiler, so they are limited by the speed of that. Dev/test build can use the built-in libtcc JIT which is super fast.
You noted AI creating a large amount of this code base with yourself directing it. Do you have a process that keeps you sane while doing this over such a large codebase?(especially for a brand new concept and implementation) [Obviously congrats and can't wait to read through to have deeper questions!]
A big part of this making it base the code of this new compiler on my previous compiler for the Lobster Programming Language. I had it go thru that codebase, distill an elaborate code style guide from it, and used that to make it write the new code pass by pass in that style. That made me feel "at home" as if it is my code, easier to review etc, and easier to know we're going in the right direction by seeing similar structure to my past compiler work.
Once the initial compiler was there it became easier, as Fable is rather good of working within the context of what is already there.
Thanks much appreciated!! Feeling silly for not noticing my best experience with AI in larger/complex cases has been languages/frameworks that are opinionated in usage/design(zig/go/elixir/rust)
Way off topic, but I enjoyed Amiga E. And, I reckon you're one of a handful of people I would take seriously when they say, "I made a new programming language."
It does not currently offer automatic AOS -> SOA transform, you'd have to do that yourself. I did look into it, but doing it automatically is not a great fit with how Goose tracks arrays. Maybe can be reconsidered at some point.
Given we are getting to the point where coding agents write most of the code, what motivates you to create a new programming language? Follow up: do you build these languages keeping humans in mind, or are these meant to be used by AI agents?
I've been making languages all my life, and I made this one because I had a really strong design in mind that I think should exist.
Whether it would make sense in this AI world was not a consideration.
The syntax and semantics were mostly designed for humans. That said, using it optimally asks a lot of the human, and in turns out the better LLMs don't break a sweat using it, so maybe it accidentally hits the spot. Goose with LLM can give you lots of speed without the effort.
In some weird way it is a great time to make new languages, because the downside of convincing humans to learn it is gone. Anyone that has a project that needs to be fast can decide to use Goose for it at very little cost.
Thanks for your response. I have been wanting to dip my toe in the space of language building for a while, but keep getting discouraged by the advances of coding agents. Love your reason for building this!
> I made this one because I had a really strong design in mind that I think should exist.
Yes, the compiler guarantees references to data structures can't escape. I believe it does that "perfectly" :)
It certainly requires the programmer to rethink how they structure their data, as you have to think of where it is going to be stored, and how to store it in a way such that it will have similar lifetimes to what it is stored with, to get the most out of the language.
The extra "than" in front of "safe Rust" is superfluous and reads like an error, as if there's a comparative adjective missing ahead of it. I don't see any situation where "and than" should ever appear in any non-contrived English sentence.
What happens if the memory is freed in a different order to allocation? Does the language disallow that? Or does it get allowed but mean the stack can't shrink?
The compiler automatically optimally allocates all arrays currently in scope that are able to grow to "stacks" (address spaced reserved areas).
The programmer choose what to store where, so you typically store things in arrays by lifetime. Goose gives you many more tools to do that, it can store entire variable sized trees of an enum type in a single array.
You try to avoid having to deallocate in mixed/random order, but if you absolutely must, you can turn arrays into pools, basically.
I'm a bit confused about how you could decide the number of stacks at compile time. I can see you could see how many arrays are lexically in scope. However if the code puts one dynamic array inside another dynamic array I can get to an unbounded number of total stacks without ever needing more than two in lexical scope at once. Do you also add stacks at runtime? Like a stack of stacks?
Probably kernel code, or cases where allocation randomization is important. Seems like with goose you may end up executing more deterministically (but still it can randomize where these N data stacks start), but because it's single threaded workers (in essence), all data construction would follow the same pattern, hence an attacker (something snooping your memory) would know easier where things would be.
I think they have slightly different places on the "speed vs ease of use" pareto frontier.
With Goose, the core design favors speed over everything else. Though not only was I able to make that safe, it is fairly pleasant to use. But it remains a low level systems language that requires you to think hard about data organization.
Lobster is a waaay more high level language made to be pleasant to use first, fast second. Surprisingly though, it can get pretty close in speed to C++/Rust nowadays too, but still a lot slower than Goose.
Do you have plans to continue using AI to improve Lobster too, e.g. working on implementation speed, or perhaps self-hosting?
How have you found AI at writing Goose or Lobster code, if you give them a skill or something, are they relatively competent at actually writing code in the language?
Both are really interesting projects, BTW - thank you! I've been meaning to try Lobster out but haven't found time, I think this might be the push I needed.
Part of this is that 64-bit address spaces make this design practical, and almost all languages in use today were designed with the limitations of 32-bit in mind. Once you can assign arrays huge amounts of address space, you don't have to realloc, which gets you stable pointers, and a lot of the other Goose features.
I've named many of my past languages with animal names, e.g. Lobster.
Goose just popped into my head as cool sounding at the time.
It has no special meaning.
Most of my current Goose projects are games, not surprisingly, but I have some language/tooling ideas as well.
As for Amiga E, I am very proud of having made it way back when obviously, but it doesn't stack up against my more modern languages (Goose and Lobster), so I think I'll leave it be :)
I would throw the entire docs out and write it from scratch in your own words. I get that we live in an era where the machine writes most/all of the code, and I can accept that. What I need, to even consider using and extending this project, is some understanding of what part of the design is yours and what part is accident by Claude. I can't get that from reading Claudese.
>>I get that we live in an era where the machine writes most/all of the code
Only on the Internet is this true, not in real life. I cannot and do not trust any of these things to do a proper job because they have not in any situation succeeded in any job I've given them. And no company I deal with claims otherwise
Right I feel like they just got to a point where they can reliably write individual functions with direction. Every time I've tried to use them consistently I feel like I just end up spinning wheels from them doing things that mostly work until it crashes and burns or just has straight up missing things or half truths. Skill issue or not it doesn't work for me.
Still glad I basically never have to debug a build issue or memory error again though
If the Code is bad, you can tell it to fix it to match your expectations —only at the edges, are you going to have to spell it out.
Lack of documentation used to be a running joke.
The goose_spec.txt in 2019 would be "goose is like c and rust only with syntax like array{;}[] btw it uses a small amount of stacks instead of malloc."0 10klocs.
Now, we make sure the AI leaves documentation so it can figure out what it was doing earlier.
A local model a few generations and many weights behind newest Claude can implement my novel algorithms and write the documentation I wouldn't.
Yes, many times it does dumb CS for kindergarten mistakes but it only has to work towards the optimum every once in a while.
That's like me with violins!
2 replies →
it's definitely true in real life. i think there is actually a massive skill gap in using them effectively.
I can see that you only work with true scotsmen, but the machine really does write most of the code now, at least from a pure numbers perspective.
Eh, I think the tutorial is pretty readable? It's concise enough.
With the tutorial, the summary also makes more sense. I have not read the other parts yet, but so far I like what I see.
All is in pretty good taste, and I like what I've seen so far. I do not care if the author himself came up with the idea, or if AI came up with it and the author approved.
I do not understand why you "have to" know this to make use of it. You can judge ideas independently of where they came from (and you should).
This is actually a really good point that I think many people fail to understand these days!
The version of the documentation which I would very much like to see would be a Literate Programming version where all the code is explained from the ground up.
Apparently, this can actually assist the LLM:
https://news.ycombinator.com/item?id=47300747
That's a great idea. I wonder if any major library (or language) has attempted a version their site in that style.
I'd love to experiment with this myself.
I do not think you know who this guy is
Once a week, I tell Antigravity (3.8-flash) to rewrite every code comment and documentation that was changed in the past week. Neither GPT nor Claude can write like a human.
Neither can Gemini.
We as a society have to cut this low effort commenting out. The documentation is perfectly comprehensible. What action would you take differently if a given feature were implemented by Claude, or a human?
If you've ever been tasked with coming up to speed on a system mostly documented with AI writing, you'll quickly realise how hard it is to trust anything you are reading. Even if the Claude documentation is 100% accurate, you'll never shake the worry that some crucial fact you founded your understanding on was wrong. It's a fast recipe for psychosis.
That's without even mentioning that AI writing can often state the what but not the why. That human perspective is usually the most valuable knowledge to get across in writing.
7 replies →
As I said in my message, it would determine whether I use the project or not. I need to match it to my use cases, and if I find a match I need to know: is it matching because my use case falls in the domain of what the human collaborator wants from this project, or is my use case a hallucination that will go unsupported?
You cannot tell either from the AI written docs. I'd rather OP gave a rambling post about some problem he has in gamedev that led him to think a new language was needed, why the constraints are different, and how this will improve X, Y, or Z in his own words. Then I can infer what this project is and where it is going. Right now, I have no clue.
13 replies →
Comprehensibility does not equal correctness or fitness. As if that wasn't enough, or perhaps in most related manner, an LLM/AI cannot be held responsible for what it produces, by nature, especially considering the fact that a _human_ claims all of it as their own work, or at least take responsibility. Meaning that when a parable of documentation is discovered to be bogus, you can't pin it on AI, you go to the human and ask them why the documentation is wrong, and it's not a good look.
Why are low effort comments not worthwhile but low effort docs are fine?
> The documentation is perfectly comprehensible
For a programming language? It's subpar and you know it.
See this for a language docs site by a small-ish team, but a significant effort was put into making it nice to read: https://tour.gleam.run/everything/
> What action would you take differently if a given feature were implemented by Claude, or a human?
This one is easy: I'd read the docs if it were written by a human, but I won't read them if they're written by Claude.
I find your comment much much lower effort than GP you took a snip at. It's true that more ppl may align in your thinking, but dissing the other side's concern as low effort does not belong in hn.
And ... you made Lobster lang, Cube2/Sauerbraten 3d shooter and voxray/voxile and lots of other cool things.
https://strlen.com/
And not to forget Amiga E language...really cool stuff
Oh wow this takes me back. We had very poor internet connectivity when I was growing up, so my brother and I played Sauerbraten and a handful of other games exhaustively with a crossover cable strung between our rooms.
Sauerbraten is such an amazing game. Every so often I boot it up and play some venice instafrag
What does this mean (from your link):
> Nested data stays inline. A string, an array of strings, a record with variable-size fields and an array of those records are each one contiguous block with no pointer in it. A record that is 160 bytes and an allocation in C++ is 29 bytes and none in Goose.
I’m having trouble parsing that last sentence.
It means that to do variable sized things like vectors and strings, C++ often ends up having to allocate their contents dynamically. Which results in data structures with lots of 64-bit pointers over multiple allocations.
Even Rust's "enum" feature, which can store different sized things all in the same space, does that at the cost of the smallest variant being just as big as the biggest.
Goose can do all of that not only inline (no pointers), but with variable size, meaning small items take less space. It's like a serialized data representation, but iterable. It makes for big space savings vs these languages.
As far as I can tell, you're essentially creating a new stack for every dynamically-sized variable (because otherwise nothing would be able to grow by bump allocation without moving). But this means you're creating a separate virtual memory allocation for each of these objects, which (I presume?) then rounds the size up to the OS's minimum page size (4KiB or similar).
Doesn't that waste a lot of space? Or is there something I'm missing?
Also it would seem to force every allocation to go through the OS kernel to allocate unless there's some trick to avoid that.
7 replies →
These AI generated docs would make more sense if you instruct it to not include numbers unless they form a complete example.
I wish it was more clear about the memory layout of nested variable sized data structures. As far as I can work out the max capacity is decided at construction time which makes the whole thing a lot less intriguing.
I parsed it as "A record that is ((160 bytes and an allocation) in C++) is ((29 bytes and none) in Goose)."
So, I read it as, "C++ uses 160 bytes and an allocation, when Goose requires 29 bytes and no allocation".
> 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.
how to perform this copy without atomics?
do the workers run as threads or processes?
also you claim it's faster than rust and c++. but for certain kinds of software it's certainly (and substantially) slower, right?
The copy is made by the runtime, which obviously does use atomics underneath, but you don't ever use these yourself.
The workers are threads. The separate memory is the concurrency model, but it's still single process, multiple threads.
The "faster than" is on average, and both in my own benchmarks and independent benchmarks you can find examples of algorithms where it is slower, but they tend to be the exception. "substantially" slower I haven't found yet.
https://kostya.github.io/LangArena/#/top_tab
> The "faster than" is on average, and both in my own benchmarks and independent benchmarks you can find examples of algorithms where it is slower, but they tend to be the exception. "substantially" slower I haven't found yet.
Well message passing with literal memcpys (rather than, say, just a shared buffer, like is common in Rust) is very expensive when the messages are huge. Of course as the message size increases, the Rust program will become faster than the Goose one (and if it doesn't, you should look into your benchmarks)
Being more specific, it means that for each message, we are writing on memory twice - one to build our own buffer with the message, and another to make a copy to another worker. Message passing violates, in spirit, the Goose rule that things are built on their end destination: we can't write into a buffer owned by another task, so we need to first write on our own buffer, and then do a copy, which is a lot like first writing the value to the stack, then copying the heap. Writing twice has an overhead, specially when messages don't fit in the cache - you just need benchmarks with sufficiently large messages to demonstrate it.
Beyond that, there are some algorithms that can be made much faster when written with atomics rather than message passing. (Also there are algorithms that will get faster if you use locks! Locks aren't always slower). It's just a matter of finding such examples, and writing a Rust code that will use atomics, compared to a Goose program that uses messages between workers because Goose doesn't expose atomics to the user.
So if you didn't find such examples, it's because you didn't specifically write benchmarks with those scenarios in mind (or, I mean, didn't told your LLM to write this).
That is: if the Rust program and the Goose program do the same thing in the same way, then it's reasonable that Goose is faster on average. But Goose is limited because it doesn't let you do some things, but Rust does, so to compare the languages you need to find those cases where the Goose limitations end up making the software slower
That site is just benchmarking how well an AI can implement things, it has nothing to do with how "fast" the language is.
1 reply →
Sounds like they are processes, as the docs say that all the global data is duplicated for the workers to have a private copy.
I have my own language I'm working on in private and it's nice to see other people coming to the same conclusion on region based memory. I was heavily influenced 7 years ago from learning from HandmadeHero and the community around it, and so I made that memory model one of my goals from the start, and it is indeed possible to get very fast programming with it when you make it your default, and when you make the language able to statically analyze it more.
That is about where our similarities end, though, since I'm doing quite a lot of other stuff in the midst as well (much heavier type stuff, fully incremental, retargetable, reflection, integer range tracking, blah blah blah), and the more goals you have, the complexity blows up exponentially. I do think that the region based memory part alone is worthwhile to have as a language feature, so I applaud your pragmatism. I like your syntax for returning through call stacks, too.
There are other languages that do this, though. Did you look into any of the others? Or ones like Odin which give you the configurable bump allocators and scratch space as well? Mainly I'm curious about your opinions of prior art.
it's too late to edit but i saw the prior art on github now https://github.com/aardappel/goose/blob/master/docs/design/p...
anyway, hope this project goes well! the secret of the arena allocator seems to be out now to the mainstream. I think this is also a strength of array programming languages in the tradition of APL/J/K/Q.
As this project develops, I'll get to benefit from your public crowd sourced testing and design before having to publicize mine :P
Yeah, my language in development uses only arenas for memory management too. But this Goose language is next level.
I will take a better look at Goose some time later when it's not late at night. Just wanted to drop by and thank you for creating Treesheets. I haven't given its more advanced features the use they deserve, but I love it as a note-taking application for anything that complexity-wise sits between a short outline in a plain text file and a ton of Markdown in something more advanced like Obsidian. And for, of course, any tabular data.
Hah cool, small world :)
In this example does it compile if you write return inside the block right below w (where the error occurs)? https://github.com/aardappel/goose#safe-references-no-annota...
Hows the compile time? Do you have a number or is it similar to another language?
Good question, not sure without testing. Likely it will still give the error. It could elide it, but I am not sure how useful that is.
Optimized builds go thru the local C compiler, so they are limited by the speed of that. Dev/test build can use the built-in libtcc JIT which is super fast.
You noted AI creating a large amount of this code base with yourself directing it. Do you have a process that keeps you sane while doing this over such a large codebase?(especially for a brand new concept and implementation) [Obviously congrats and can't wait to read through to have deeper questions!]
A big part of this making it base the code of this new compiler on my previous compiler for the Lobster Programming Language. I had it go thru that codebase, distill an elaborate code style guide from it, and used that to make it write the new code pass by pass in that style. That made me feel "at home" as if it is my code, easier to review etc, and easier to know we're going in the right direction by seeing similar structure to my past compiler work.
Once the initial compiler was there it became easier, as Fable is rather good of working within the context of what is already there.
Thanks much appreciated!! Feeling silly for not noticing my best experience with AI in larger/complex cases has been languages/frameworks that are opinionated in usage/design(zig/go/elixir/rust)
Way off topic, but I enjoyed Amiga E. And, I reckon you're one of a handful of people I would take seriously when they say, "I made a new programming language."
Thanks, that brings me back, haha :)
You might want to update https://strlen.com/language-design-overview/ at some point.
Haha yes, haven't updated my website in a while :(
Where does the language stand in the array-of-structs vs struct-of-arrays choices? Does it offer an annotation to choose that like in Zig?
It does not currently offer automatic AOS -> SOA transform, you'd have to do that yourself. I did look into it, but doing it automatically is not a great fit with how Goose tracks arrays. Maybe can be reconsidered at some point.
Given we are getting to the point where coding agents write most of the code, what motivates you to create a new programming language? Follow up: do you build these languages keeping humans in mind, or are these meant to be used by AI agents?
I've been making languages all my life, and I made this one because I had a really strong design in mind that I think should exist.
Whether it would make sense in this AI world was not a consideration.
The syntax and semantics were mostly designed for humans. That said, using it optimally asks a lot of the human, and in turns out the better LLMs don't break a sweat using it, so maybe it accidentally hits the spot. Goose with LLM can give you lots of speed without the effort.
In some weird way it is a great time to make new languages, because the downside of convincing humans to learn it is gone. Anyone that has a project that needs to be fast can decide to use Goose for it at very little cost.
Thanks for your response. I have been wanting to dip my toe in the space of language building for a while, but keep getting discouraged by the advances of coding agents. Love your reason for building this!
> I made this one because I had a really strong design in mind that I think should exist.
Is this like forcing the escape analysis of the compiler to be perfect, by making it explicit in the programming language?
I'm wondering what kind of architectural corners this forces the programmer into ... have you found any so far?
Yes, the compiler guarantees references to data structures can't escape. I believe it does that "perfectly" :)
It certainly requires the programmer to rethink how they structure their data, as you have to think of where it is going to be stored, and how to store it in a way such that it will have similar lifetimes to what it is stored with, to get the most out of the language.
Interesting, I'll play with it. In the "Why Goose" section there is a mistake I guess : "Faster than C++ and than safe Rust, while memory safe."
I don't think it's a mistake. He's claiming that it's faster than C++ and it's faster than safe Rust.
The extra "than" in front of "safe Rust" is superfluous and reads like an error, as if there's a comparative adjective missing ahead of it. I don't see any situation where "and than" should ever appear in any non-contrived English sentence.
Why would that be a mistake?
What happens if the memory is freed in a different order to allocation? Does the language disallow that? Or does it get allowed but mean the stack can't shrink?
How are you deciding how many stacks to use?
The compiler automatically optimally allocates all arrays currently in scope that are able to grow to "stacks" (address spaced reserved areas).
The programmer choose what to store where, so you typically store things in arrays by lifetime. Goose gives you many more tools to do that, it can store entire variable sized trees of an enum type in a single array.
You try to avoid having to deallocate in mixed/random order, but if you absolutely must, you can turn arrays into pools, basically.
Thanks!
I'm a bit confused about how you could decide the number of stacks at compile time. I can see you could see how many arrays are lexically in scope. However if the code puts one dynamic array inside another dynamic array I can get to an unbounded number of total stacks without ever needing more than two in lexical scope at once. Do you also add stacks at runtime? Like a stack of stacks?
3 replies →
What are some use cases (if any) that the language is not suitable for?
Probably kernel code, or cases where allocation randomization is important. Seems like with goose you may end up executing more deterministically (but still it can randomize where these N data stacks start), but because it's single threaded workers (in essence), all data construction would follow the same pattern, hence an attacker (something snooping your memory) would know easier where things would be.
Do you consider Goose to be a replacement for Lobster, or do they fill different niches?
I think they have slightly different places on the "speed vs ease of use" pareto frontier.
With Goose, the core design favors speed over everything else. Though not only was I able to make that safe, it is fairly pleasant to use. But it remains a low level systems language that requires you to think hard about data organization.
Lobster is a waaay more high level language made to be pleasant to use first, fast second. Surprisingly though, it can get pretty close in speed to C++/Rust nowadays too, but still a lot slower than Goose.
Do you have plans to continue using AI to improve Lobster too, e.g. working on implementation speed, or perhaps self-hosting?
How have you found AI at writing Goose or Lobster code, if you give them a skill or something, are they relatively competent at actually writing code in the language?
Both are really interesting projects, BTW - thank you! I've been meaning to try Lobster out but haven't found time, I think this might be the push I needed.
5 replies →
First, Congrats on the release!
Do you know if Goose is the first time something like this has been done?
In this particular combination, most certainly.
There is lots of prior art on the individual parts of the design, e.g. "regions" and various stack languages etc, see: https://github.com/aardappel/goose/blob/master/docs/design/p...
Part of this is that 64-bit address spaces make this design practical, and almost all languages in use today were designed with the limitations of 32-bit in mind. Once you can assign arrays huge amounts of address space, you don't have to realloc, which gets you stable pointers, and a lot of the other Goose features.
Why was it named Goose?
I've named many of my past languages with animal names, e.g. Lobster. Goose just popped into my head as cool sounding at the time. It has no special meaning.
I feel the need, the need for speed. Talk to me, Goose.
Thank you.
If you had no other obligations and todos getting in the way, what's the first thing you'd rewrite in Goose yourself?
(And why isn't it Amiga E?)
Most of my current Goose projects are games, not surprisingly, but I have some language/tooling ideas as well.
As for Amiga E, I am very proud of having made it way back when obviously, but it doesn't stack up against my more modern languages (Goose and Lobster), so I think I'll leave it be :)
Why are you pretending that John is endorsing your project?