January 2, 2026

Closure Wars: Graphs, Gripes & Giggles

The Cost of a Closure in C: The Rest

C fights over ‘fake’ closures, weird graphs, and why not just use C++

TLDR: The article benchmarks clever ways to imitate closures in C, showing real performance differences across hacks like static and thread‑local variables. Commenters fought over fundamentals: some say “C has no closures,” others shout “use C++,” and chart nerds nitpicked confusing graphs—because performance debates matter to real code.

This new benchmark blitz dives into how folks fake “closures” in C—little helpers that carry extra context along with a function—by trying tricks like extra arguments, static variables (shared per program), and thread‑local storage (per thread). It matters because old C tools like qsort can’t take a handy “user data” pointer, so these hacks keep the original shape of the function while sneaking data in. The author says the performance isn’t the same, and the community immediately turned it into a spice rack of opinions.

Top comment? A purist declaring “C does not have closures”, basically accusing the article of closure cosplay. The chart cops showed up too: one reader grumbled the axes were baffling and demanded log scales and decibels—yes, actual decibels for code charts. Meanwhile, the C++ crowd barged in yelling “just use std::sort” (the C++ sorting tool) instead of wrestling with qsort. And then a Lisp fan tossed a grenade: macros fix closure speed there, but please don’t make C macros do that—because everyone’s seen how wild C macros get.

Between performance graphs and philosophy fights, the funniest meme was: why benchmark tricks when you can switch languages? Bonus nerd nod: a “Rosetta Code” variant got a shoutout here, and yes, someone will definitely argue about that too.

Key Points

  • Benchmarks were rerun with 150 repetitions for 100,000+ sample iterations to improve statistical robustness.
  • New Plain C categories include extra-argument functions, a Rosetta Code pointer-based variant, static-variable context passing, and thread_local context passing.
  • Static variable approach preserves function signatures but is not thread-safe; thread_local preserves signatures and is thread-safe.
  • Signature preservation matters for interoperability with legacy APIs like qsort and for FFI use cases.
  • Benchmark implementations are publicly available, and initial expectations of negligible differences are challenged by measured performance variations.

Hottest takes

"C does not have closures" — andsoitis
"std::sort from C++ is much better" — Panzerschrek
"I wish more people would know about decibels" — userbinator
Made with <3 by @siedrix and @shesho from CDMX. Powered by Forge&Hive.