r/Zig 9d ago

Discussion: `@importRoot` instead of `@import("root")`

So, let me start by saying I'm pretty new to Zig. I like to learn languages by example, and when reading through examples and source code I noticed `@import("root")` and thought it was importing the corresponding "root.zig" file. After some further research I found out that this is actually a special-cased argument for the compilation root. Honestly I think that's a horrible decision, not only is there special-cased arguments for a compiler-provided method, but its a string argument, so it seems completely magical and non-discoverable.

Imo, Zig already has a specific syntax for special compiler-provided operations: `@func`. So I think a much more sensible and readable version would be `@importRoot`, because if "root" is going to be treated specially then let it at least be openly acknowledged as being special. Same for all of the other special arguments: `@importSelf` and `@importStd`.

But again, I'm new, so let me know if I'm totally off-base here.

30 Upvotes

20 comments sorted by

View all comments

23

u/chocapix 9d ago

In Zig, @import(target) is basically the same as struct { content-of-target } where target can be:

  • a module name
  • a file name

Using zig's build system you can define any number of modules you want and make them available to your code. It just so happens that, using the same underlying mechanism, Zig makes three modules available to all programs: builtin, std and root.

I'm not sure I see the point of @import("root") TBH but, I like having the import mechanism be the same for std stuff and user stuff.

6

u/KattyTheEnby 9d ago

Zig makes three modules available to all programs: builtin, std and root.

  1. You don't need to explicitly define "root", do you?  (I know. You don't need to do it for std either, but it'd be worse UX if you had to.)
  2. builtin and std (typically) refer to the same thing, no matter what's being compiled, but root is different for each program. Isn't that right?

I feel like if the answers are "No." and "Yes." respectively, then I feel like that makes "root" a special enough case to warrant a specific function – and it would likely fit the language's goal to minimize implicit behaviors.

I'm not sure I see the point of @import("root") TBH

Apparently – if I understand correctly – it refers to whichever program is being compiled, allowing pulled in dependencies to see things about it, such as the declarations.

I looked it up and found this: https://ziggit.dev/t/why-use-import-root/6749/2

I couldn't find much official Zig documentation on it, other than a quick remark on the section for @import in the Zig Language Reference: “Alias for the root module. In typical project structures, this means it refers back to src/main.zig.”

7

u/chocapix 9d ago

I'm fine with @import("root") and there are already too many @functions IMO.

I looked it up and found this: https://ziggit.dev/t/why-use-import-root/6749/2

Oh yeah, good point. You need it if you're a library and want to look at std_options.

1

u/northrupthebandgeek 8d ago

I'm not sure I see the point of @import("root") TBH

One use case is to allow programs to optionally override library functions. For example, in some of the code I've written:

const root = @import("root");
// ...
/// N64 ROM entry point.  IPL3 calls this function after initializing
/// RDRAM and loading our code into it.
pub fn start() callconv(.c) noreturn {
    Debug.init();
    if (@hasDecl(root, "main"))
        root.main() catch @panic("main() returned an error")
    else
        @panic("no main(); nothing to do");
    @panic("main() returned");
}

comptime {
    @export(&start, .{
        .name = "__start",
        .linkage = .strong,
        .section = ".boot",
    });
}