When a suspending function makes another suspending call, it allocates a Continuation to remember its state in case the called function suspends.
This happens even for tail calls, even though it is not necessary to maintain the function’s state in that case – it would be fine to pass through its continuation parameter instead of allocating a new one. Presumably the tail call Continuation is allocated just to produce a stack trace when an exception is thrown.
It would be great to be able to avoid this overhead in performance-sensitive code, even if that means the calling function might be missing from some stack traces. There is a
tailrec keyword that seems like it should really enable these kinds of optimizations at the cost of stack trace omissions, but it doesn’t work for this case. Is there another way?
For context, I’m writing suspending replacements for Java IO streams, and one of the goals is performance – I’d like to be able to pump N data through a whole filter chain without allocating O(N) Continuations. I ended up finding a good way without this optimization, but it seems like this sort of optimization would still be useful in many other situations.