upvote
You can also just do that in C++. I do that as part of my messaging usually, so that the objects are trivially relocatable and reinterpret-castable. It only works so long as you combine a set of canonical types, but that can be verified or converted using C++26 reflection.

I have both what I call inline sequences, and out-of-line ones (store an offset to the object itself rather than pointers).

I made all my sizes and offset 32-bit, but I suppose they could have been 16-bit.

reply
This is also the default C behavior.
reply
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.

reply
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).

reply
The obvious question is how does it work for linked lists, trees, and other non-stack-shaped data structures?
reply
At the end of the day trees are still stored linearly in memory. Think of it as an array, with each node an element of the array, and indexes used rather than pointers.

Plenty of trees only ever grow. And that's the normal type of array in Goose. However you can also have arrays that can grow and shrink, if you have a tree that is constantly in flux.

Either way it'll be one stack for an entire tree.

reply
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.

reply
What’s the “pool” case? A function allocates a growable arena in normal heap or virtual memory?
reply
All it's doing is allocating address space. And 64 bits means you have an astronomical amount of that. It only needs to become actual memory when you use it. A page at a time.
reply
> All it's doing is allocating address space. And 64 bits means you have an astronomical amount of that.

No, you can typically only assume 48 bits of virtual address space; the kernel takes half of it, so really only 47 bits. Newer CPUs provide 57 bits (e.g., Zen 4) or 52 bits (certain ARM64 models). And that's provided that the kernel plays ball; apparently some Android configurations only support 39 bits of user virtual address space.

reply
These AI generated docs would make more sense if you instruct it to not include numbers unless they form a complete example.
reply
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.
reply