3 ms·
> Again, no interaction with the outside world? Or are all inputs recorded during the entire execution? Inputs would need to be cached (eek, if there’s a lot o
by dkersten 6y ago
> Again, no interaction with the outside world? Or are all inputs recorded during the entire execution?
Inputs would need to be cached (eek, if there’s a lot of state loaded from external services or databases, or if that state is sensitive and you want to control where it may get persisted), but more importantly, output needs to be not output on the rerun (eg database writes and api calls).
> So recursion cannot depend on input from the outside world?
I’ve made a few mini languages (mostly for fun or for myself, but also external DSLs for end users) and I’m a big fan of not allowing unbounded loops. (Although bounded by a dynamic value like an input or the length of a runtime list is ok, so not quite the same thing as described here, it just needs to know the number of iterations before the loop begins) It makes it much easier, in my opinion, to prevent bugs, but of course it does mean you give up expressive power, so while it works for DSLs it’s not great for general purpose languages. I’m also a big fan of synchronous programming languages. I made one that basically runs inside a database transaction and reruns on conflict.
- wizeman 6y agoSure, but they are not simply saying that they do not allow unbounded loops, that is what some languages do already, like Coq. They are saying that the compiled program "uses constant stack space, eliminating any possible out-of-stack issues". This seems impossible unless recursion cannot depend in any way on inputs from the outside world. Mind you, even if you have constant stack space that does not mean that you won't run into an out-of-stack issue. You can still run out of stack space if it is constant, because it might not fit in memory. It would probably be trivial to construct such a program. Furthermore, a program with constant stack space may even run out of stack space during execution (due to the kernel overcommitting memory, for example).
- gliese1337 6y agoThere is a difference between "running out of stack memory" and "running out of memory used to store stack-structured data". Any recursive algorithm can be mechanically transformed into an equivalent iterative algorithm that uses only a single activation record on the system call stack. If you perform that transformation on an entire program, then the total depth of the call stack is a static property of the call graph in the source code, and it does not depend in any way on run-time inputs from the outside world. The only way to run out of stack space then would be to write a program whose static, constant stack space requirements are indeed too large for the machine it is run on. Transformed algorithms may, of course, require "manually" tracking data in a stack structure, and use of such a data structure may indeed result of running out of memory depending on what inputs are provided, but that's just "running out of memory, which we happened to be using to hold a stack-like data structure", not "running out of stack".
- wizeman 6y agoTo me it just seems that you're arguing semantics... I mean, what is the difference between "stack memory" and "heap memory allocated to store the stack", other than the fact that the OS preallocates the first one for you by default? To me, "the stack" and "a stack-like data structure stored in the heap that is used as a stack to replace what would otherwise be the stack" is functionally the same thing... You know that (given appropriate conditions) you can just allocate stack frames wherever you want and point your stack pointer to whatever you want, whenever you want, right? This is what the Go compiler does to prevent Go programs from running out of the stack space provided by the OS by default. But AFAIK they don't advertise that Go programs use constant stack space and you don't have to worry about out-of-stack issues... So as far as I understand, there is no transformation that would make any recursive program use "constant stack space", unless of course, you just use some other memory to store what you'd store on your stack (but then again, that doesn't mean your stack has constant space, it just means that you're not using the default OS-provided stack space as a stack, and you're using other memory as a stack instead). Apart from that, as I said before, even if you had "constant stack space" it does not mean that you won't have out-of-stack issues.
- gliese1337 6y agoTo me it just seems that you're arguing semantics... The most important type of argument to have. If you don't agree on semantics, no other discussion is worth having, as you will never know if the other party actually agrees with you or not. I mean, what is the difference between "stack memory" and "heap memory allocated to store the stack", other than the fact that the OS preallocates the first one for you by default? That is a pretty major difference with wide-ranging effects on program performance right there. To me, "the stack" and "a stack-like data structure stored in the heap that is used as a stack to replace what would otherwise be the stack" is functionally the same thing... System-level error messages and memory managers both disagree. You know that (given appropriate conditions) you can just allocate stack frames wherever you want and point your stack pointer to whatever you want, whenever you want, right? Yes. And once you do, that memory becomes functionally privileged from the perspective of your allocation strategy. This is what the Go compiler does to prevent Go programs from running out of the stack space provided by the OS by default. But AFAIK they don't advertise that Go programs use constant stack space and you don't have to worry about out-of-stack issues... Of course not. Because they actually use that space as stack space, to store function activation records.
- dkersten 6y agoAbsolutely, there is a big difference between compile time statically known stack size and bounded loops. Hell, loops can be bounded but dynamically sized. If they, indeed, mean that the stack is known ahead of execution, then you are absolutely right, as long as you can have recursion that depends on user input, the stack cannot be known statically.