HN
Today

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

The concept of Tail-Call Optimization (TCO) in C is surprisingly recent, with modern compiler support only solidifying in the 21st century after decades of C's existence. This revelation sparks a robust debate among Hacker News users, questioning whether TCO is a mere performance tweak or a fundamental semantic requirement for reliable recursive programming. The discussion delves into compiler history, language design, and the practical implications of guaranteed tail calls across various programming paradigms.

99
Score
83
Comments
#4
Highest Rank
20h
on Front Page
First Seen
Aug 10, 12:00 PM
Last Seen
Aug 11, 11:00 AM
Rank Over Time
455719192024202224252727292323252825

The Lowdown

This Hacker News discussion centers on an LWN.net article highlighting the relatively recent advent of effective Tail-Call Optimization (TCO) in C compilers. While often perceived as a long-standing feature, robust TCO in C, particularly for indirect calls, became a reality much later than many realize, fundamentally changing how certain recursive patterns can be safely and efficiently implemented.

  • Historically, the C calling convention, where the caller removes stack arguments, complicated TCO implementation.
  • Mark Probst introduced TCO to GCC in 2001, initially with limitations like not supporting indirect calls.
  • More recently, modern GCC and Clang compilers have achieved better TCO support, enabling techniques previously impractical, such as those used in systems like Gforth.
  • MSVC also lagged, adding TCO only in the 2010s, contrasting with languages like ML or Scheme that had mandated TCO much earlier.
  • The improved TCO support opens doors for C programmers to utilize recursive patterns, like state machines implemented as functions, without immediate stack overflow concerns.

The article and subsequent discussion underscore how compiler evolution can shift practical programming paradigms, making previously risky or inefficient recursive techniques viable in a language like C.

The Gossip

Optimization's Obligation or Semantic Struggle?

Many commenters debate whether TCO is merely a compiler optimization or a critical semantic feature. The core argument is that if code relying on TCO crashes due to its absence (e.g., stack overflow), then its presence is a semantic requirement, not just a performance boost. This leads to discussions about language specifications, compiler guarantees, and proposed attributes like `[[gnu::musttail]]` or Rust's `become` keyword to explicitly enforce or diagnose TCO.

Compiler Chronology Conundrum

Commenters jest and seriously discuss the title's claim that TCO in C is 'relatively recent.' Some point out that 2001 (GCC) or even the 2010s (MSVC) is still a significant portion of a compiler's lifetime, especially for those who began programming after these dates. Others argue that 'recent' is subjective, particularly for veteran programmers, and that the practical usability of TCO in C has only truly matured in later years due to initial restrictions.

Linguistic Latitudes of TCO

The discussion extends to TCO support and challenges in other programming languages. Examples include JavaScript, where TCO was added and then removed due to implementation issues, leading to 'stack-overflow bugs.' Common Lisp is mentioned as a potential 'footgun' for Scheme programmers expecting guaranteed TCO, though some implementations like SBCL handle it well. Rust's proposed `become` keyword for explicit TCO guarantees and C#'s dependency on JIT behavior are also highlighted.

Practical Patterns and Predicaments

Several comments explore the practical applications and limitations of TCO. While some argue that many tail-recursive patterns in C can be more naturally expressed as loops, others emphasize TCO's importance for interpreters, state machines (especially mutually recursive functions), and continuation-passing styles, where an iterative approach might be less straightforward or even impossible without significant stack management. The debate also touches on calling conventions and their impact on a compiler's ability to perform TCO.