Software Development

Zig’s Comptime and the Case Against Hidden Control Flow

Metaprogramming without a second language: no preprocessor, no macros, no separate mental model to learn.

Zig’s own homepage states its design philosophy in one blunt sentence: “There is no hidden control flow, no hidden memory allocations, no preprocessor, and no macros.” That’s not marketing copy so much as a direct rebuke of two things most systems programmers have simply learned to live with, C’s text-substitution preprocessor and the macro systems that grew up around languages that came after it. Andrew Kelley started Zig on February 8, 2016, with a specific complaint: too much of what a program actually does is invisible at the point where you’re reading it. Comptime, Zig’s mechanism for running code at compile time, is the alternative Zig built instead of adding a macro system, and it’s worth understanding on its own terms rather than as a footnote to Rust or C.

What “Hidden Control Flow” Actually Rules Out

The manifesto is more specific than it sounds. Zig has no operator overloading, so a + b can never secretly call a user-defined function the way it can in C++ or Rust; if you see a function call in Zig, a function is being called, and if you don’t, one isn’t. Zig has no exceptions, so there’s no stack unwinding happening somewhere you can’t see in the source; errors are ordinary values wrapped in an error union type, and propagating one requires the visible try keyword at every single call site. Allocations work the same way: there is no global allocator quietly backing your data structures, every function that needs to allocate takes an allocator as an explicit parameter, so a memory allocation is a line of code you can point to, not an implementation detail buried three layers down a call stack.

Comptime: One Language, No Separate Dialect

Where C reaches for the preprocessor and Rust reaches for macro_rules! or a procedural macro crate, Zig reaches for comptime, and the entire pitch is that comptime code is just Zig code, evaluated by the compiler instead of the CPU. The same syntax, the same type system, the same error messages. A generic function looks like this:

fn max(comptime T: type, a: T, b: T) T {
    return if (a > b) a else b;
}

type is a first-class value in Zig, so comptime T: type is an ordinary parameter, just one the compiler resolves before code generation rather than at runtime. There’s no separate template syntax to learn the way there is in C++, and no attribute macro expanding into code you have to run a separate tool like cargo expand to actually see. What you read is what runs, just at a different time.

C preprocessorRust macrosZig comptime
Operates onRaw text, before parsingToken trees (declarative) or a separate program (procedural)Ordinary, typed Zig code
Type-checkedNoOnly after expansionYes, the same as runtime code
Separate syntax to learnYes, its own mini-languageYes, matcher syntax or the proc-macro APINo, it’s Zig
Debuggable with normal toolsRarely, errors point at expanded textOften not without extra toolingYes

Where the Borrow Checker Doesn’t Fit This Story

It’s tempting to place Rust’s borrow checker in the same “hidden” category as macros, but it’s a different kind of thing entirely, and Zig’s manifesto doesn’t really compete with it. The borrow checker isn’t generating code or expanding text, it’s a static proof that runs silently over your whole program to guarantee no two mutable references to the same data can exist at once, a genuinely powerful piece of compiler reasoning that happens without you writing anything extra. Zig opts out of that category of power altogether rather than offering a competing version of it. Memory safety in Zig leans on runtime checks, bounds checks, checks for use of undefined memory, that are present in Debug and ReleaseSafe builds and compiled out in ReleaseFast and ReleaseSmall, a trade-off the language is explicit about rather than something it tries to hide. Kelley has put the positioning plainly: “Zig is not trying to be Rust. Zig is trying to be a better C.” The comparison that actually holds is narrower than “which language is safer,” it’s “which language makes you learn a second dialect to do compile-time work,” and on that specific question C and Rust both answer yes, while Zig answers no.

Desired: developers who want to use the language next year. Admired: developers who used it and want to continue. Source: 2025 Stack Overflow Developer Survey, Technology.

Zig, still pre-1.0, posts an admiration score of 64.2 percent among the developers who’ve actually used it, edging out Elixir and trailing only Rust among languages in this comparison. That’s the pattern usage data tends to show right before a language’s adoption curve steepens, a small group of people who’ve tried it liking it disproportionately more than the general population has heard of it.

Real Momentum, Not Just Enthusiasm

The clearest evidence that Zig has moved past hobbyist curiosity is who’s paying for it. Bun, the JavaScript runtime built substantially in Zig, and TigerBeetle, a financial transaction database, each donated $60,000 to the Zig Software Foundation in 2024, the kind of check a company writes when a language is load-bearing infrastructure, not a side experiment. ZML, an inference platform, gave $33,000. HashiCorp co-founder Mitchell Hashimoto personally pledged $300,000 spread across 2024 and 2025. None of that money came from venture capital or a corporate parent; the Zig Software Foundation, a nonprofit Kelley founded in 2020, runs entirely on donations and reported total 2024 income of $670,672.59 against expenses of $520,748.91.

Corporate donations to the Zig Software Foundation in 2024, among its largest listed sources. Source: Zig Software Foundation, 2025 Financial Report.

The clearest recent signal of a community large and confident enough to act on its own principles came in November 2025, when Zig moved its entire canonical repository off GitHub to Codeberg, a nonprofit git host, with no mirror left behind, citing GitHub Actions reliability problems and a conflict with Zig’s policy against LLM-generated contributions. At the time of the move the repository carried more than 43,000 stars and over 3,000 forks. Walking away from that kind of visibility on the platform most open-source discovery still runs through is not a decision a small, uncertain project makes lightly.

The Manifesto Has a Cost

None of this makes comptime free of trade-offs. Zig’s refusal to add operator overloading or a trait-like constraint system for generic parameters means comptime type errors can surface as long, unfamiliar compiler output when a type doesn’t support an operation deep inside a generic function, a complaint with real precedent in C++ template error messages before that language added concepts. Zig accepts that cost deliberately: the alternative, some kind of constraint or interface system layered on top of comptime, would itself be a small addition to the language’s surface area that the “no hidden anything” philosophy is built to avoid.

When comptime’s philosophy actually fits your project

  • You want generics, conditional compilation, and code generation to use one syntax, not three
  • Reading a function call and trusting that it’s really just a function call matters more than operator sugar
  • You’re comfortable trading compile-time aliasing guarantees for explicit, visible allocation and error handling
  • You can tolerate a pre-1.0 language, current releases are still in the 0.x beta series, in exchange for a smaller, more legible mental model than C’s preprocessor or Rust’s macro system

What We Learned

Zig’s “no hidden control flow” manifesto and its comptime mechanism are the same idea applied consistently: metaprogramming, generics, and conditional compilation should use the language you already know, not a second one bolted on beside it. That’s a genuinely different answer to compile-time flexibility than C’s preprocessor, which operates on raw text before the compiler even understands types, or Rust’s macro system, which trades that same problem for a token-tree or proc-macro API most developers only partially internalize. It’s also a narrower answer than Rust’s borrow checker, which Zig doesn’t compete with at all, opting for visible runtime checks over an invisible, if powerful, static proof.

The real evidence Zig’s bet is paying off isn’t the manifesto itself, it’s that companies with production systems riding on the language, Bun and TigerBeetle among them, are now paying its nonprofit foundation’s bills, and that the community was confident enough to walk away from GitHub entirely rather than compromise on its principles.

Eleftheria Drosopoulou

Eleftheria is an Experienced Business Analyst with a robust background in the computer software industry. Proficient in Computer Software Training, Digital Marketing, HTML Scripting, and Microsoft Office, they bring a wealth of technical skills to the table. Additionally, she has a love for writing articles on various tech subjects, showcasing a talent for translating complex concepts into accessible content.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Back to top button