The Goose Programming Language

(aardappel.github.io)

138 points | by bobbydigitales 3 hours ago

35 comments

  • Aardappel 2 hours ago
    Btw I made the language, AMA. repo: https://github.com/aardappel/goose
    • koolba 2 hours ago
      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.

      • Aardappel 2 hours ago
        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.

        • eslaught 1 hour ago
          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.

          • vanderZwan 1 hour ago
            I think what you might be missing is that you can also do a sort of livenes analysis to determine how many dynamically-sized variables are "awake" at the same time at most. Then you only need to create as many stacks as that number, because you can reuse the stacks of "sleeping" variables (since the "awake" variables are guaranteed to be freed once their block goes out of scope, and threads don't share any memory so no data race worries regarding those stacks).

            For example, suppose we have a function with a growable array that calls another function (without passing said array) that also uses a growable array as some temporary scratch space. Then the first function's array isn't being used when the second is sleeping, so the inner function's array could safely share the stack because it will all be freed with a single pointer restore once the second function exits.

            Now, I actually don't know how the compiler works but as I understand it does things similar to my example to optimize the number of stacks needed (but let's wait for WvO to confirm or deny whether my understanding matches reality).

          • Aardappel 1 hour ago
            Only top level growable arrays get their own "stack", if you create an array of arrays it only uses one stack.

            How you deal with the inner stack growing depends, ideally they don't grow (construction only), or you can make them fixed size, or with a capacity, or in the worst case, as a pool. The language has facilities for all of these.

            • amluto 2 minutes ago
              What’s the “pool” case? A function allocates a growable arena in normal heap or virtual memory?
        • koolba 2 hours ago
          These AI generated docs would make more sense if you instruct it to not include numbers unless they form a complete example.
      • lynndotpy 2 hours ago
        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".

    • nextaccountic 2 hours ago
      > 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?

      • Aardappel 1 hour ago
        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

    • AnEro 2 hours ago
      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!]
      • Aardappel 2 hours ago
        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.

        • AnEro 1 hour ago
          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)
    • amelius 2 hours ago
      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?

      • Aardappel 2 hours ago
        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.

    • fancyfredbot 2 hours ago
      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?

      • Aardappel 2 hours ago
        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.

        • fancyfredbot 1 hour ago
          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?

          • Aardappel 1 hour ago
            The top level arrays all are owned by a local variable. An array of arrays is just allocated to a single stack.
            • fancyfredbot 1 hour ago
              I'm sorry if I'm being dense here but I can't see how that would work?

              The spec on your GitHub says: "Two simultaneously-live resizable values never share a stack."

              So I surely can't have a dynamic array of dynamic arrays share a single stack? That's an unbounded number of resizeable values sharing a stack?

              You could make it work on a single stack but that would involve having non-contiguous memory for each inner array since you can add to any array in any order.

              The spec implies that we need one stack per element of the outer dynamic array which would let you have contiguous memory for each inner array, but you wouldn't know how many stacks you needed at compile time.

    • lemming 2 hours ago
      Do you consider Goose to be a replacement for Lobster, or do they fill different niches?
      • Aardappel 1 hour ago
        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.

        • lemming 1 hour ago
          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.

          • Aardappel 1 hour ago
            I've already been improving Lobster's speed a lot in recent times: https://github.com/aardappel/lobster/blob/master/tests/compa...

            Self-hosting would be cool too, but for both Lobster and Goose I've tried to keep it simple for people to build the language in any environment, which is why its still all in C++.

            I don't use any "skills". From what I can see, the #1 way an AI produces "good code" is to simply work in the context of existing good code. I don't need to hold it by a style guide, it seems to infer that from context just fine. At least Fable does, other models less so.

            • vanderZwan 1 hour ago
              > From what I can see, the #1 way an AI produces "good code" is to simply work in the context of existing good code.

              "Just Git Gud First" - Wouter van Oortmerssen

    • ksec 2 hours ago
      First, Congrats on the release!

      Do you know if Goose is the first time something like this has been done?

      • Aardappel 2 hours ago
        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.

    • jdw64 47 minutes ago
      Why was it named Goose?
      • Aardappel 14 minutes ago
        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.
    • vanderZwan 2 hours ago
      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?)

      • Aardappel 2 hours ago
        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 :)

    • groundzeros2015 56 minutes ago
      Why are you pretending that John is endorsing your project?
  • malisper 1 hour ago
    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

    • Aardappel 1 hour ago
      Certainly, this is a language where you get the most benefits if you are able to structure your data usage such that things of similar lifetimes sit together in arrays.

      For example, you can build up a tree of all variable sized nodes inside a single array.

      Where it gets interesting is if you must arbitrarily delete tree nodes, and you can't structure it to do that in stack order. The language has various tools for this, like fixed arrays with capacity, or pools of either single elements or runs of elements.

    • progval 1 hour ago
      I'm not familiar with Goose, but I'm guessing you could define a single stack and put your dynamically sized values in it. Essentially rewriting a memory allocator on top of Goose's stacks. This is what they seem to be doing here: https://github.com/aardappel/goose/blob/master/samples/13_li...
      • malisper 1 hour ago
        Yeah, that looks like a freelist approach. That will work as long as the values you're allocating are all fixed-size. You'll need something much more complicated if you want arbitrarily sized values

        That example implements a linked list of integers. I'm curious how you would do a linked list of strings

    • andsoitis 1 hour ago
      > how would you represent a hash table where the values are strings and at random, the program inserts or deletes a random string?

      Goose has a built-in generic hash table called dictionary<K, V>, provided by its standard library.

      https://aardappel.github.io/goose/docs/stdlib.html#dictionar...

      • malisper 1 hour ago
        From the link

        > Keys and values are fixed-size

        so not quite what I'm looking for

        • andsoitis 1 hour ago
          You can store the strings separately and have the dictionary hold references to them.

          Conceptually:

          dictionary<i64, StringReference>

                       |
          
                       +----> "hello"
          
                       +----> "a much longer string"
          
                       +----> "x"
          • MeetingsBrowser 1 hour ago
            Isn’t this just re-inventing the index arena pattern, which nullifies much of the benefit over rust?

            > Goose code holds typed references where the equivalent Rust holds u32 indices into an arena — and it is where a good share of the benchmark wins come from.

    • James_K 1 hour ago
      I think the limit of this would be creating your own allocator that works with the stacks, but you could probably stop short of that in most cases.

      It's not entirely mad to do it this way, and I can see some benefits. For one, you might have multiple of these pools across the program for different data-types, which would make allocating to any one of them a cheaper operation. It is much more reference safe since you are only ever freeing stuff in a certain context and you can still never have dangling pointers. When you look at memory safe languages, they all default to this eventually. Like Rust in the advanced case will have you implementing your own allocator, lot's of games use this thing called ECS which is essentially a kind of allocator. Goose would just have it be more common.

      • malisper 1 hour ago
        This is roughly what I do in Rust. I use different static types for values based on how long they'll live. Temporary values get one type; cached values get another. The allocator allocates each value in a different location based on how long the value will live.
  • pradn 1 hour ago
    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…

    • Aardappel 45 minutes ago
      You typically "allocate only" if a data structure is made entirely on construction, or if its growth is bounded.

      If it is potentially completely unbounded, you need different solutions like a pool, or essentially reconstructing etc.

  • bobbydigitales 3 hours ago
    "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

  • ebiederm 2 hours ago
    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?

    • Aardappel 2 hours ago
      Yes, ML Kit region inference is probably the closest prior art to Goose.

      Back then though, they couldn't lean on large 64-bit address spaces like Goose can. They implemented all of this with a chain of blocks of memory instead, and tracked most of it at runtime that Goose now does at compile time.

      https://github.com/aardappel/goose/blob/master/docs/design/p...

  • anigbrowl 2 hours ago
    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.

    • Aardappel 1 hour ago
      Thanks!

      The name is an animal because all my past PL designs are animals (I also made Lobster etc). Goose seemed like a fun name.

  • Aardappel 1 hour ago
    I made the language, AMA :)
    • pixelesque 40 minutes ago
      Without wanting to be snarky, are the "hand optimized" C++ benchmark files mentioned on the benchmark page available anywhere, as the ones in the "bench/cpp/" directory don't look that optimized to me?

      e.g. I see a general lack of reserve()s on strings and vectors (a few tests do use them a bit, like `graph` and `particles`), and there are several other things which I wouldn't personally call "optimized", so I assume those ones are the 'idiomatic' ones?

      Same goes for the Rust code: a lot of the code seems to be using Vec::new() and String::new(), instead of ::with_capacity() which would optimize the memory re-allocation (reducing it as the containers/strings grow).

      • Aardappel 21 minutes ago
        Yes indeed, the real hand optimized files are private, the ones in the repo are decoys.
    • jnpnj 54 minutes ago
      Was it your first programming language ?

      ps: Ah well, I could have searched before asking https://strlen.com/programming-languages/

      super neat history !

      • Aardappel 40 minutes ago
        Haha yeah no, I'm afraid I keep making new ones! :P
    • onlyrealcuzzo 1 hour ago
      If you mentioned it in the main page, I didn't see it.

      Something that I'm interested in: How fast is the compilation speed on large programs compared to Zig, C, Go?

      My ideal language is safer than Rust (no deadlocks / livelocks, no stack overflow from recursion), is optimized for cache locality, but compiles faster than Zig.

      This seems like it's close to 2/3.

      • Aardappel 38 minutes ago
        The current implementation goes thru an optimizing C compiler as backend for "shipping/production" builds, which will limit how fast we can make it compile.

        That said, during development/iteration/testing, you can just the built-in JIT, which is based on libtcc (which is very fast), as don't as you don't mind a ~3x runtime slowdown.

    • dash2 36 minutes ago
      Do you think it would be worth writing the landing page yourself? The concepts seem interesting but it's painful to wade through stuff like "One memory model: stacks, and scope exit is the free".
      • Aardappel 17 minutes ago
        I've already edited it plenty, but I guess it doesn't bother me that much.

        I preferred people being able to play with it rather than worrying about any claude-isms :)

    • briandw 1 hour ago
      Fantastic project BTW! How much AI help did you have with this project? I'm assuming some. If so is it something that you would have taken on before AI help?
      • loufe 35 minutes ago
        There's a section at the bottom called "History & Use of AI". Please do your part to keep the discussion here honest and healthy, if not a read of the post, at least a ctrl-f would have been sage.
  • pulse7 2 hours ago
    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...
    • malisper 2 hours ago
      I'm not familiar with Goose, but based on some research and my understanding of how memory works:

      At compile time, Goose will analyze your program and determine a number of stacks, N, for it. N is the maximum number of "growable" items you can have in existence at any given point in time. Using virtual memory tricks, each stack can grow up to 2GB, but it uses a contiguous address space and only uses as much physical memory as it actually needs.

      For the program you're describing, I think you would end up with two stacks: one to parse the input and a second to print it. When you parse the input, Goose reads characters from the string one at a time and puts them onto the stack. Once it has hit the end of value, it will update the stack so it now represents the decoded JSON value (strings will just leave the characters in place, numbers will pop off the characters and push the number onto the stack). Goose repeats this until it has parsed the whole JSON, and now the whole JSON is on the stack.

      Then, when you print the JSON, Goose uses the second stack to build a string. Like the parsing approach, it iterates through each element of the JSON and pushes its string representation onto the stack. Once it's done, it resets the stack pointers to free the memory.

      This is really nice because allocating memory is just adding to the pointer, and freeing it is subtracting from the pointer.

      In contrast, Rust automatically inserts malloc() and free() calls throughout your code, which are much more expensive than pointer arithmetic. On top of that, freeing a vector of heap-allocated objects is O(n), whereas if done right in Goose, it would be O(1)

    • Aardappel 1 hour ago
      https://github.com/aardappel/goose/blob/master/samples/18_js...

      Goose can store entire trees (of variable sized things) inside an array.

    • andsoitis 2 hours ago
      > How is memory for JSON allocated on stack?

      Check the features section (https://aardappel.github.io/goose/#features), which starts off with how memory works.

    • stickfigure 2 hours ago
      I don't see why this is problematic. Stack is just memory, you can allocate it by incrementing a pointer. Any amount you want, really.

      Apache modules worked like this (still do, presumably). Each request has a stack; allocations bump the stack pointer; when a request is finished, the stack pointer is reset. Incredibly efficient as long as you don't need to keep memory longer than a single request.

      Looks like in Goose, each scope acts like an apache "request".

      • abcd_f 2 hours ago
        In Windows, by default, thread's stack is capped at 1MB. Main thread gets more but that's somewhat off the point.
        • stickfigure 1 hour ago
          Stack size is completely arbitrary, just like heap size. You have 2^64 addresses to work with.
  • AnEro 2 hours ago
    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.
  • weinzierl 2 hours ago
    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.

    • Aardappel 9 minutes ago
      Goose has no "unsafe" feature, and no undefined behavior, and is fully memory safe.

      It is obviously has a lot of potential to be very fast.

      It even does pretty good on DX. There is no borrow checker to fight. Algorithms that need indices in Rust are strongly typed references in Goose. Generally pleasant easy to read and write code.

      The biggest thing against DX may be exactly where performance comes from: you need to think a bit on where to store your data :)

    • vanderZwan 1 hour ago
      Well, "safety" is a lot of things so you have to be a bit more specific than that about your use-cases. And I can't really answer it either way - I think WvO has to chime in about that himself - but I can point to some things that might give you some idea of what to expect. Here's what WvO wrote a few weeks ago when he shared Goose on twitter:

      > Goose: my latest programming language. Safer, faster and less memory than Rust/C++ for algorithms where tightly packed, flat data structures matter.

      > It can represent more kinds of data structures as flat, pointer-free bytes than any language I know.

      https://xitter.cf/wvo/status/2107979660558766351

      So one way to answer might be: how often do you reach for unsafe when using Rust? If you don't I guess Rust is safer. If you do… it gets trickier.

      As for UB, I guess you could try looking through the spec and/or the reference? Like, the code is mostly generated by Claude after WvO wrote a specification. If it were anyone else I'd be worried, but given WvO's cv I actually suspect that means the spec leaves basically no ambiguity.

      However, Goose compiles to C. Does that by definition mean UB sneaks in, or is there a "UB free" C subset? I don't write C, so I don't really know.

      • weinzierl 1 hour ago
        I guess my question is if you can trigger UB in regular Goose and if you can, would it be considered a bug. I realize that this doesn't necessarily have a simple yes or no answer but I still think it'd help to know if Goose is more on the C++ side or the Rust side.

        The complete omission of UB in the README could be one of two things. Either that the topic is not important or that it is considered a given and not worth mentioning.

        • vanderZwan 1 hour ago
          Hmm, well the benchmarks always use an explicit "faster than idiomatic C/C++ and safe Rust". Similarly it also notes that in theory you could write equally fast C/C++ (since Goose compiles to C), but it would be an unreadable, unsafe mess.

          Note also the fact that e.g. array indexing has bounds checks without escape hatches for the programmer, but the compiler can elide quite a few of them, and the language has tools to help the programmer write code that is guaranteed to be check-free.

          I think that suggests the ambition is to compete with Rust in the domain of combining safety with not compromising on performance.

  • kadw 1 hour ago
    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!

    • Aardappel 1 hour ago
      The language as it stands actually uses relatively little physical/committed memory, so could be used in embedded systems, but does rely on there being a 64-bit address space, which is probably still not as common in embedded.
  • daoxid 1 hour ago
    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?
    • malisper 1 hour ago
      Goose determines where the array will be copied to at compile time and allocates it there.

      Rust does a similar thing. When a function returns a value, a location for it will be put in the callers stack frame. That means it automatically stack-allocates values when feasible. The downside in Rust is you need to know the size of the value at compile time whereas Goose can do it for arbitrarily sized values

  • andsoitis 2 hours ago
    Lobster is the author's other programming language, previously discussed on HN: https://news.ycombinator.com/item?id=47239955
  • FrankWilhoit 2 hours ago
    The right ideas. Not optimized for reallocation. Creates pressure to overload types, making secure software unattainable.
  • calvinmorrison 22 minutes ago
    Can someone explain the weird phrasing here "Nothing moves, so references survive growth" that AI does.
    • Aardappel 7 minutes ago
      Almost all languages rely on reallocation when a growable array grows, which means you can't store pointers to elements, as they get invalidated upon a reallocation.

      In Goose, things grow in-place only, since they have a large amount of address space reserved.

      • calvinmorrison 2 minutes ago
        no i mean literally the sentence structure
  • groundzeros2015 57 minutes ago
    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”.
    • Aardappel 43 minutes ago
      You can see from his comment that he apparently went to the Goose repo and read it. What he references is neither in his original tweet nor my reply.
      • groundzeros2015 32 minutes ago
        The headline is misleading. He hasn’t been commenting about the Goose language and his experience with it. And you are promoting.
  • timcobb 1 hour ago
    > One memory model: stacks, and scope exit is the free

    What are the ergonomics of this I wonder.

  • pron 1 hour ago
    Interesting, but can you write something like an LRU cache?
  • skrebbel 1 hour ago
    I love that the logo is a very fast goose
  • gigatexal 1 hour ago
    Would be interesting to see Luke’s Zed language from the replies on HN.
  • baalimago 2 hours ago
    Do android dream of goose?
  • rfgplk 2 hours ago
    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.
    • gspr 22 minutes ago
      > 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.

      So now your safety and performance issues are in the LLM and whatever prose you feed it for it to generate slang. Have you gained anything?

      (Not meant to detract from the language. It's just that this particular goal seems... strange).

  • rvz 1 hour ago
    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.

  • FrustratedMonky 2 hours ago
    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

    • tobiolo 2 hours ago
      I think it is a general systems programming language that fits for a variety of use cases but especially well with trees, records and where you want to have direct data (de-)serialization, like flatten out a tree and pick it up then (last one reminds me of FlatBuffers, another invention of the programming language author). I think if you look into the Discord channel there's some nice examples.
  • ethanhood_okroh 1 hour ago
    [flagged]
  • mi_lk 2 hours ago
    Obviously the guy is replying to something that you can't see without logging in twitter. And without context this means little
  • anonymous908213 2 hours ago
    [flagged]
  • mihaaly 2 hours ago
    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
  • iacuobos 2 hours ago
    I can't see a reason to use this and not C++ It reads like slop text
  • IshKebab 2 hours ago
    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.
    • ivanjermakov 2 hours ago
      I like it this way, it gives correct expectations regarding effort put into the rest of the project.
  • geoffbp 2 hours ago
    No relation to https://goose-docs.ai/ I guess?