- Why doesn’t zig have header files?
- Why does C have header files?
- It seems like most modern languages don’t have header files, why?
C header files share common definitions and declarations between C files.
Also it was easy to implement #include
as part of the C preprocessor.
Rob Pike explains the Go language design in: Go at Google: Language Design in the Service of Software Engineering. From the pain points and dependencies we can understand that the replacement of header files and includes by import statements have to do with faster compilation and controlling dependencies.
Zig tries to fix C problems; zig replaces the C preprocessor, see: The Road to Zig 1.0 - Andrew Kelley
Isn’t the burden of proof the other way around? Why have header files?
I guess the answer to all these question is simply “The C preprocessor”.
- Why doesn’t zig have header files?
There is no preprocessor or forward declaration requirements in Zig.
- Why does C have header files?
A long history of strict memory requirements that pushed C language designers to “single pass compiling”.
- Zig has a concept of modules
- C does not have a concept of modules. It uses headers to avoid code duplication. But they are not required, technically.
Bingo. It was brilliant at the time, given the constraints, but those constraints no longer apply today.
I could possibly use some advice here, because in my own projects, I seem to prefer header files for one main reason: documentation. When I go back to code I haven’t worked with recently, being able to skim the declared interfaces on a single screenful, without having to wade through implementation details is a real pleasure.
I guess some people use editors that can fold implementations, but I’ve never managed to get that to work right.
Regarding C, isn’t the main reason header files exist is that the language separates declaration from definition? Declarations have to be in scope at the call site, but definitions don’t need to be known until link time.
There is fold
in (doom)emacs, works out of the box. Easy to call and read. Tho its more keyboard-oriented so theres no bullet to toggle in this one.
It has been stated that C doesn’t really have header files because they technically aren’t any different from source files. What C has are forward declarations. In my understanding, that is what really makes header files a thing.
This really is true!
There’s a very specific way to use folding to make reading code much simpler, but it generally isn’t well supported out of the box. Everyone has “folding”, but only IntelliJ has a single checkbox to fold function bodies. nvim makes it relatively painless to do it yourself though https://old.reddit.com/r/neovim/comments/1g41rjy/can_neovim_do_this_already_with_treesitter/ls0cf4b/, though, for Zig specifically, some ingenuity would be required to come up with a useful tree sitter expression to filter out “generic types” which you don’t want to fold.
Sorry - necroposting. I’ll look at the date next time.
Given how old C is, perhaps the design choice was influenced by Lisp? The macro processor in Lisp was very powerful, perhaps the designers felt that preprocessing was just automatically a good thing?
I must admit, if Zig had header files … I would have looked elsewhere. I hate them. I even find that features like precompiled headers are things that I have to constantly introduce team members to.
IMHO the one good thing about C header files is that they provide a compact overview of the API (because they strictly separate the API declaration from the implementation). Theoretically IDEs or autodoc-systems should provide the same type of overview by extracting public symbols from the API, but they can’t beat a manually written header file because they don’t know what’s important.
Case in point, the sokol_gfx.h API only has a handful of ‘important’ structs and functions which one needs to know in order to work with the API. I can structure a header so that the importants parts of the API stand out and related parts are near to each other.
But when looking at the autodocs it’s just a soup of declarations with the important stuff somewhere inbetween:
https://floooh.github.io/sokol-zig-docs/#sokol.gfx
E.g. sorting the autodocs alphabetically is absolutely the least useful thing to do, because you already need to know what you’re looking for (e.g. it’s only useful as a reference, but not as documentation)
“An Ode to Header Files” / Josh Haberman. - January 27, 2025
This could be improved both by adding a (more comprehensive) //! documentation comment
to the top of the module, and by Zig docs generator to create better-sorted & grouped list of symbols that isn’t nearly so cryptic. (Displaying their doc comments would be a start).
But the easiest way to improve discoverability of public API would be to put implementation details into nested, “private” module. In a way this makes the top-level module akin to a header file, but with much less repetition.
Great point about source order being significant to documentation. It’s also significant for type reflection, by the way.
Since autodocs is an app, it can show both, with a keyboard shortcut for switching sort modes.
I don’t think the proposed feature is quite as simple as sorting, however. It also means mixed modes - you might have some types, then some functions, and then some more types, then some more functions. In other words the source order sort would also be “mixed” mode.
Totally doable, if it’s worth the implementation cost.
I would say that the goal of autodocs should be to achieve something that is strictly better than header files for documentation, which would imply this feature is worth it.