F# as a language is great for writing language interpreters or compilers, however, one thing keeps hitting us where we don't want it: the StackOverflowException.
It's well known that an SO-exception cannot be caught and cannot be recovered from. An obvious technique for preventing such an exception is by counting the depth of the stack as you go along. Overhead, yes, but doable and perhaps not necessary in every function.
With F#, this technique doesn't bring much benefit though. We make a lot of use of tail-call optimization techniques in the on-the-fly generated expressions of the interpreter. The problems we face with SO-exceptions are:
- how can we inform the user of them, instead of crashing the whole current AppDomain?
- if we go for counting the stack-depth, how do we know whether a function is TCO'ed or inlined so we don't have to count up?
- if we go for another approach (like inspecting the stack itself at given depth-intervals), is there any (known) way to do this without seriously impeding performance?
Just increasing the stack-size is not going to help enough, we want to give the user a loggable error, preferably catchable by the calling application. For that we need to be able to hand-throw the exception, which makes it catchable. But how do we determine the right moment?
Update:
Hans Passant correctly suggests predictability here. However, the programmers using this DSL expect that (certain) calls get TCO'ed, hence they don't want a strong stack-limit. They know what they are doing. Still, their programs need to be able to die gracefully, at least to the extend that any calling application (i.e., a C# program using our libraries)
is not harmed.