Live data from Hacker News

Tail-call optimization in C is relatively recent (2025)

lwn.net

41–50 of 129 posts

Re: Tail-call optimization in C is relatively recent (2025)

#41
post #15

I think Anton is replying to me in that LWN article IIRC. I personally didn't know C only had tail calls that late and learnt something new there! On the other hand, I am pretty new to the compiler space myself, and I count early 2000s as a pretty long time ago, though again it is not that far back considering how long other language implementations had tail calls like in ML or variants since 1980-90s.

It still doesn't, this is a compiler specific language extension. You won't find anything on ISO/IEC 9899:2024 about tail calls, like it happens on Scheme. https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3220.pdf Section 3.5 of R7RS. https://standards.scheme.org/official/r7rs.pdf

Woops, I meant to write tail call optimization not tail calls. Shouldn't have used the term interchangeably. Yeah I'm aware that C doesn't have proper tail calls. Thanks for the correction though.

Re: Tail-call optimization in C is relatively recent (2025)

#42

Unless the language can guarantee TCO, I don’t feel comfortable writing tail recursive code and being at the compiler’s/interpreter’s mercy. I think the framing of TCO as an optimization has been very unfortunate.

It's hard to argue that it isn't an optimization, because it doesn't affect the semantics of the program. However most optimizations are very hard to observe. The vast majority of optimizations only affect code size and runtime. TCO is one of the few exceptions. It affects memory usage, and more sensitive stack memory at that. This is why a missed optimization can be so much more catastrophic and it is worth consider…

> It's hard to argue that it isn't an optimization, because it doesn't affect the semantics of the program.

Depends on the semantics of the programming language itself. For some languages, it is truly an optimization, for some, it is required, and does meaningfully change observed semantics.

Re: Tail-call optimization in C is relatively recent (2025)

#43

Unless the language can guarantee TCO, I don’t feel comfortable writing tail recursive code and being at the compiler’s/interpreter’s mercy. I think the framing of TCO as an optimization has been very unfortunate.

Some languages have TCO annotation, it throws compiler error if TCO fails. You want stronger type system, not smart compiler guarantees or promises!

Re: Tail-call optimization in C is relatively recent (2025)

#44
post #27

Earlier quoted context omitted.

MSVC stands for MicroSoft Visual C++ compiler AFAIK. It famously doesn’t support a few features of C99. They don’t really seem to care much about regular C support (non-C++).

They officially saw no need for C support going forward. https://herbsutter.com/2012/05/03/reader-qa-what-about-vc-an... Note, "If you really need either of the following.....then we recommend that you consider using a different compiler such as Intel or gcc (short-term) and/or pressure your standards committee representatives to have ISO C++ include more of the C standard (longer-term)." Which is kind of why nowaday…

TIL, thanks for updating me on this!

I read Herb Sutter’s post many years ago, but didn’t know they had picked up the work again.

I see that VLAs are still not supported, which is a shame IMO, but the C-support seems much better than it used to be at least.

Re: Tail-call optimization in C is relatively recent (2025)

#45
post #32

Earlier quoted context omitted.

I am not a Clang expert, but first, obviously that's a C++ attribute and so while Clang can decide what it means in Clang in the programming language itself it has no semantic weight because the ISO document says attributes are always ignorable. Secondly however in these languages you often won't naively get TCO because you have at least one local variable which C++ would say has a "non-trivial destructor" or Rust wo…

Reordering destructors is not safe in C++, as it's fairly common to rely on objects being destroyed in reverse order and doing stuff like A a; B b(&a); In rust the borrow checker would guard against reordering such things, but a caveat is that there might be unsafe code relying on drop-order which the borrow checker would be oblivious to. There could also potentially be objects representing external resources like a…

> In rust the borrow checker would guard against reordering such things

It doesn't even get that far: Rust guarantees that things drop in reverse order of declaration, full stop.

One interesting wrinkle here: for struct members, Rust does the opposite of what C++ does. We debated changing it to match, but

> there might be unsafe code relying on drop-order which the borrow checker would be oblivious to.

There was no super real compelling argument to choose one direction over the other in the abstract, and "be the same as C++" was not considered important enough to risk breaking unsafe code that relied on the (what was at the time) implementation defined behavior.

Re: Tail-call optimization in C is relatively recent (2025)

#46

Unless the language can guarantee TCO, I don’t feel comfortable writing tail recursive code and being at the compiler’s/interpreter’s mercy. I think the framing of TCO as an optimization has been very unfortunate.

It's hard to argue that it isn't an optimization, because it doesn't affect the semantics of the program. However most optimizations are very hard to observe. The vast majority of optimizations only affect code size and runtime. TCO is one of the few exceptions. It affects memory usage, and more sensitive stack memory at that. This is why a missed optimization can be so much more catastrophic and it is worth consider…

JVM does a lot of escape analysis to turn heap allocated memory into stack local variables.

It doesn't matter if it's local since it's a VM, it's doing it at runtime and can change an entire call stack of non local code for an optimization.

Re: Tail-call optimization in C is relatively recent (2025)

#47
post #3

Earlier quoted context omitted.

Lack of TCO is also a common footgun for Scheme programmers using Common Lisp.

This footgun is the reason I'm so enthusiastic about the Rust `become` keyword. This proposal would give Rust a specific keyword which says that you intend TCO and so two things happen: 1. The compiler goes to more length to deliver TCO even where it wouldn't "just work" and 2. If it cannot deliver TCO your code doesn't compile, because you asked for TCO.

Does 1 really happen? I would never trust a compiler where 1 was a possibility. If it can work it should.

Re: Tail-call optimization in C is relatively recent (2025)

#48

Unless the language can guarantee TCO, I don’t feel comfortable writing tail recursive code and being at the compiler’s/interpreter’s mercy. I think the framing of TCO as an optimization has been very unfortunate.

It's hard to argue that it isn't an optimization, because it doesn't affect the semantics of the program. However most optimizations are very hard to observe. The vast majority of optimizations only affect code size and runtime. TCO is one of the few exceptions. It affects memory usage, and more sensitive stack memory at that. This is why a missed optimization can be so much more catastrophic and it is worth consider…

The main difference is not that it affects memory usage, imo.

It’s that it makes memory usage bounded when it’s on, and unbounded when it’s off.

In languages that have guaranteed tail call eliminations, the semantics of tail recursion is the same as that of a loop. So you can express the same iterative algorithm without using iterative code.

Re: Tail-call optimization in C is relatively recent (2025)

#49
post #36

Unless the language can guarantee TCO, I don’t feel comfortable writing tail recursive code and being at the compiler’s/interpreter’s mercy. I think the framing of TCO as an optimization has been very unfortunate.

GCC has `[[gnu::musttail]] return`. But yes, framing TCO as an optimization is unfortunate.

And there's also [[clang::musttail]] and [[msvc::musttail]].

As well as an effort to get it standardized: https://isocpp.org/files/papers/D3939R0.html (in C++).

Re: Tail-call optimization in C is relatively recent (2025)

#50

Unless the language can guarantee TCO, I don’t feel comfortable writing tail recursive code and being at the compiler’s/interpreter’s mercy. I think the framing of TCO as an optimization has been very unfortunate.

It's hard to argue that it isn't an optimization, because it doesn't affect the semantics of the program. However most optimizations are very hard to observe. The vast majority of optimizations only affect code size and runtime. TCO is one of the few exceptions. It affects memory usage, and more sensitive stack memory at that. This is why a missed optimization can be so much more catastrophic and it is worth consider…

std::vector is just a terrible specialisation, it isn't an optimisation.

If std::vector was an optimisation we couldn't write C++ which blows up because it's actually a bitset, it would be semantically transparent - but that's easy to do even by accident because it's not transparent at all.

In fact the existing std::vector should just be named std::growable_bitset or something and then std::vector would make what you actually wanted like Rust's Vec does.

Post reply on HN