But with lots of threads there aren't enough spaces for them to start from. At least on 32-bit. On 64-bit I think you could have effectively infinite stack, or at least very very large (like 1 GB) stacks. But as far as I know nobody has bothered to do it.
I guess an alternative solution would be to put the stacks in different address spaces somehow, but that could get very complicated (now you have two kinds of pointers). Are there any old systems that had separate heap and stack address spaces?
But that's only because stack space is currently limited. If stack space were as unlimited as heap space then there would be absolutely nothing wrong with using as much stack space as you wanted. It would be better even - stack space is much quicker to allocate and free than heap space.
On 16-bit x86, memory was divided into 64K segments and you could have separate ones for code, data and stack. Having effectively a different address space for code isn't a problem, but languages like C expect that you can pass around pointers to stack variables as well as global/heap ones. So now every data pointer needed to be a "far" one (32 bits, segment:offset), and to dereference it the segment portion would usually have to be loaded into the single "extra" segment register that isn't dedicated to code/data/stack.
With data and stack sharing the same segment, you could use 16 bit pointers for everything and the code was a lot more efficient.
I often want stack allocation without having to worry if it hits some arbitrary limit unrelated to actual memory available. Memory is fungible.
It's true that there are programmers with different values.
Trying to do everything with tail calls in Forth puts you in a position much like any other language: Okay, you can have a single overarching state machine with top-level routines, but you can't factor anything into subroutines because there's no way to 'return'.
Progress: Fifth
Eventually N!