Hi, I just stumbled upon a news of new programming language called Goose. Please comment on it and compare with Julia.
Nice language! But does it have any libraries? Julia has thousands of packages. If it compiles to C it will not have a REPL. So for the time being the number of problems you can solve with Goose is small, and probably it will be less fun than programming with Julia.
I happened to be looking at this the other day; very interesting memory management (all on the stack), threads (separate programs), and other features. It transpiles to C, and from there you have two routes: compile through any external C compiler for maximum optimization and performance, or run through the built-in TinyCC, which compiles straight to memory (but the whole compilation unit, not incremental). So, a kind of REPL could be possible, but it would be more like old-school BASIC where you run the whole program, or use this in some sort of embedded environment.
I was comparing to Rust for low-level programming, and that itself makes it very different from Julia. As a possible transpilation target from or interpreter for Julia, there are a lot of differences (GC among them), so itâs not a great match. Definitely wonât have the same variety or amount of scientific libraries, though C-interop should be very good, so most of that should be available.
C on its own doesnât rule out a REPL or an interpreter. But yes in this case practically speaking no. But I suppose you could vibe code a different implementation that support a REPLâŚ
Iâm not sure (with current implementation), it insists on:
Whole-program compilation. No separate compilation, no shared libraries of Goose code (spec §10.1)
The bundled TinyCC backend compiles and runs a program in-process, with no build step.
conventional incremental REPL is going to be hard. [You can use any C compiler as backend, but TCC is fastest out there.]
However I did find a REPL for C:
I was looking for a REPL for TinyCC, but found:
TCC could compile the Linux kernel in 8 seconds, at one point, so maybe you could just compile most things very quickly.
Interesting design! TL;DR: memory management is handled by guaranteeing there are no heap allocations.
Iâve built a compiler that can compile anything in 0 seconds. I call it an interpreter
At first glance, it seems to have a very restrictive memory model. Doesnât this generally make it hard to write programs, compared with even C++? Itâs the exact opposite of the expressiveness provided by languages with GC.
It looks like a memory-safe systems language that does everything except the numerical work youâd have finished by yesterday in Julia.
Depends what you mean. First, Iâd note C++'s difficulty is mostly unrelated to garbage collection: thereâs lots of languages without GC that are easier to write (like Nim or Rust) and there are actually garbage collectors written for C++. The difficulty of C++ is more to do with the fact that itâs C++ than its lack of garbage collection. A better comparison than C++ is Rust: is it less âexpressiveâ? Yes. But in large part thatâs because it lacks the ability to express lots of bad coding patterns, which is often a good thing.
Thatâs a different tradeoff from Julia, but in practice the two converge a lot. In Julia, we write performant code by making sure we donât touch the garbage collector (more formally, we avoid heap allocations). That means to get good performance, we already have to write the heaviest part of our code in a similar style to Goose, with similar restrictions. That flexibility is nice, but also means heap allocations need to be found using trial-and-error on test cases, which can miss some allocations and requires lots of time-consuming profiling.
For those wondering, hereâs the relevant Wikipedia article. Goose uses an approach (similar to) ordered types, while Rust uses one (similar to) linear types (technically affine).
I have moved the question to Offtopic; it is not really a question in any case but a discussion starter. It does not belong in the General usage category, since it is not about using Julia.
There is little point in comparing this language to Julia as they implement very different paradigms, it is like asking for a comparison between a newly discovered species of butterfly and a tropical fish. Where do you start?
It would make much more sense to ask this kind of question on a C++ or Rust forum. Though I am not sure it would be welcome; this seems to be a single-author AI coded language.
Iâve read through the code a bit, and it seems that Goose doesnât have a general-purpose allocator. It only has a fixed number of âmemory poolsâ that are essentially arrays you can grow or reset, fixed at compile time, which means no vector of independently managed vectors, and so on.
This makes it really fast when the memory usage pattern is simple, but can sacrifice generality unless you implement your own inner allocator or so.
Are you sure?
A default variable-array length is
u32;T[uN]uses that unsigned width, andT[varint]uses unsigned LEB128. Static limited-array length widths are 1, 2, 4 or 8 bytes at capacities 255, 65535 and 2^32â1. Runtime limited arrays storeu32 capacity, thenu32 length, then all capacity slots; assigning one preserves the receiverâs capacity.
[Why â8 bytesâ there? Support for more than 4 GB arrays? Docs unclear.]
I (or my AI) havenât found any support for 32-bit platforms. Since you have many stacks, that would seem rather hard to do or not work well (at least with many stacks). Ancient Forth used a similar system (with ALLOT; later supporting also malloc/libc and heaps) on just one memory region, on even 8-bit micros, and yes likely didnât support variable arrays well. But if you need to grow and they donât fit I suppose you can copy an array to a new place and expand there. I suppose you need to explicitly change your pointers to the new array! For Goose I havenât confirmed, maybe you just reserve a huge array, only paying for virtual memory for each, not physical memory, and that would work well on 64-bit.
The C backend targets 64-bit, little-endian hosts with unaligned packed accesses.
Sort of related but also highly intriguing (Iâve yet to see a language with such support, maybe Julia should and its gapless, by default, structs):
varintâ variable-length integer storage type (§3.6), the only integer type restricted to fields and array elements. Reads decode toi64, and it is writable only at construction.
I suppose since you can have varint in structs the structs themselves are also variable length?!
AI tells me varint is not just for serialization as I thought: âvarint is an actual storage type in Goose, usable in struct fields and array elements.â and from docs âvarint: §3.6 (ULEB128; zigzag where signed).â
N data stacks â large virtual-address-space reservations (reserved up front, committed on use). N is computed statically by the compiler (§10.3). Each data stack is a bump pointer. Growth never moves memory; references into a data stack are stable for the life of the data beneath them.
I saw elsewhere in the docs:
GS_MAX_STACKS |
1024 | The most data stacks one thread program may use. A program that needs more fails to compile. |
|---|
TCC doesnât support threads, then you have that limitation, otherwise I read that as 1024 limit per thread. But you can have many arrays in a stack, so not a limit on arrays.
According to the github itself:
Memory is a handful of data stacks that the compiler assigns statically.
That is not a bug or something the author wants to hide. It is a feature with its set of tradeoffs.