I am using zlint and zwanzig on my Zig projects, but neither of them sorts the imports, and I like my code tidy. std.zig.Ast made my life easier building this project, can’t tell the same about trying to support both 0.15.2 and 0.16 at the same time.
AI / LLM usage disclosure
I used cheap LLMs for doing the hard work from the beginning to the end. But I have been coding since 1996, so I hope this is still not vibe coding.
I see, this is an interesting one. I have built zsort with the assumption that each import gets assigned to a const, then potentially some aliases are created.
For example, one pattern is first const a = @import(“a.zig”) followed by const x = a.x and const y = a.y, and another pattern is direct const x = @import(“a.zig”).x; of course, it is always possible to just const a = @import(“a.zig”) followed by no aliases.
zsort tries to group all of these neatly at the top of the file. If we move the entire block to the bottom, don’t we risk constants being used before they were defined?
Container level variables have static lifetime and are order-independent and lazily analyzed. The initialization value of container level variables is implicitly comptime. If a container level variable is const then its value is comptime-known, otherwise it is runtime-known.
The file is a struct with container level variables which are order independent.
Wow, I just learned something new. A const being an implicit comptime makes sense, and I do understand how you can move container-level consts around safely by that logic. Still, it requires some unlearning for people used to strict order of operations in many other languages. So I think this will probably remain a matter of taste for another generation of Zig developers. I think the cheapest and the least controversial change to zsort is a flag to push all imports to the bottom of the file, for developers of that taste. I will create an issue and pick it up on my first availability.
Third-party — other module names (httpz, sqlite, …), including @cImport
Local — paths containing / or ending in .zig, plus Zig’s package-level modules root (the package’s own root source file) and build_root (the build runner’s root module)
Aliases — const X = module.Member; where module resolves to an import above; const X = @This(); sorts first in this band
The rules i’ve been using are this:
Module imports: const std = @import("std") and const foo = @import("./foo.zig") are grouped together. std is not given any special treatment. Sorted, alphabetically if i get around to it.
That’s just my personal preference, not that i expect you to implement it. I don’t think the specifics of the rules are super important, as long as there are rules that make it so I don’t have to think about it when I add an import. The ones above work pretty nicely, so far i haven’t found any ambiguous case where I’m not sure where to put an import.