Do I get TCO here? (And is it bad style?)

I've been writing a quadtree recently, and noticed a structure that I'm curious about, specifically:

fn insert(&mut self, position: Coordinate, item: Item) {
        if let Leaf(items) = &mut self.payload {
            if Self::should_split(&items[..]) {
                // ...
            } else {
                return items.push((position, item)); 
// etc

AIUI, this is a tail call that could be optimized - the return expression is immediately another function call, so we can reuse our stack frame because there's nothing else needing done once we return from the callee. But this is also not the conventional recursion passing things up the stack, because the return type is (). Does the principle still apply and can the compiler elide the stack frame? (And is this a crime against good style?)

1 Like

I would say yes, because it had me scratching my head as to why you're returning the value of a push which I remember has no return value - when I noticed that insert has "no" return type either.
On the other hand, you don't need to be clever with the compiler to force any optimization. I don't know whether the stack frame is actually elided here. But any simple control flow analysis will show that a new stack frame is not required and my bet would be that LLVM would detect that anyway. Tail-call optimization is called so because it has to do with calling and not with returning.
Also, worrying about such micro-optimizations is colloquially the root of all evil.

1 Like

The optimizer will often optimize such things in release builds. And it'll do so regardless of whether you do return items.push(...); or items.push(...); return;. Tiny syntactic differences like that are irrelevant to the optimizer.

That said, Rust does not have guaranteed TCO. So you should never write code that depends on it for correctness.


This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.