AlexKindel
On the other hand, functions that do return something that contains one or more Integers would take a pointer to the memory pointer, so that they could increment the caller's pointer to the end of the last array that the return value references. Often, generating the return value requires allocating additional Integers that are not themselves part of the return value. Ideally, the caller's memory pointer would not be incremented in such a way that the heap memory for these temporary values falls before the pointer, preventing the caller from overwriting it. If an upper bound on the size of the return value's heap data is known a priori, this could be done by leaving an empty block of that size at the initial location of the memory pointer before allocating the local values. If no such bound is known, all Integer heap data could be allocated in the order that it's needed for the calculation, and then the parts that are needed for the return value could be copied to the initial location of the memory pointer.
A cleaner way to handle this: a function that needs arena memory both for its return value and for scratch work in generating that return value should take two arena parameters - an output_arena that is a pointer to a pointer to memory, so that the inner pointer can be incremented to the end of the region used for the output, and a scratch_arena, which is a pointer to memory so that the incrementing of the pointer that happens within the function isn't reflected on the caller's end. If a function that takes both arenas calls another function that takes both, if the result of the called function is to be part of the caller's return value, the caller would pass its output_arena and scratch_arena as the called function's parameters of the same names, while if the result of the called function is to be part of the caller's scratch calculations, the caller would pass &scratch_arena for the output_arena parameter and *output_arena for the scratch_arena one.