Recursive function - can I remove the callstack?

Let’s say I have some function:

function a()
    task.wait(1)
    print("a")
    a()
end

If I call this function, it will work 20,000 times. It will then error because the call stack limit has been reached, so the stack overflows and we get the corresponding error message. I would like to avoid this behaviour and indefinitely print “a” to the output.

while true do
    task.wait(1)
    print("a")
end

This achieves the same result, but no longer uses functions. I’m looking purely to stick to functions, so if anyone knows a purely functional workaround, that would be great.

You’re bound to add a delay to it. The limit can be lowered or increased from ScriptContext, I believe. You could use a function to check whether the code should wait by checking something with tick() (if it’s lower by 0.5 or something) or, yeah, I don’t really remember how it looked like.

Have you tried putting it in a coroutine?

I dont think you can change the limit so maybe this limit is per script thread.

Not sure how to clear the stack once it reaches a certain size, but this would work.

function a()
    task.wait(1)
    print("a")
    task.spawn(a)
end
a()

Just put that while loop in a function? Or call ‘a’ from a while loop outside the function? Or do what the others suggested and separate it by using coroutines.

The call stack is super important. It basically tells roblox where to return to when your function ends. So every time a function is called, it needs to know where it was before it was called so you can return there and not lose the flow of your program. The stack however, does have a maximum size which is throwing an error when you exceed it. There are some potential optimizations to help avoid that in some cases.

Let’s take your function for example. When you call ‘a’, roblox needs to store where you called ‘a’ from in its memory so when you leave ‘a’ it can put the program back where you left off. But now, you’ve called ‘a’ from inside the function. Now roblox has to add a new thing to the stack showing where you called it this time. It keeps doing that until the stack runs out of room and your program crashes.

In theory, since you’re never returning though roblox could just put the place where you called ‘a’ from outside the function ‘a’ on the stack. Then for every time it calls ‘a’ from inside your function, it could just share the first return location on the stack since every return value would always be nil. That way when you finally hit the end, there is only the first link of the chain it has to follow, instead of reversing every call it made.

However, luau as far as I’m aware, doesn’t do any recursion optimizations like that. So you’re stuck with the suggestions in my first paragraph.

1 Like