I’ve come across that I have no idea what @import even is.
For example, when I type fn func(x: u8) bool { const y = x + 1; … } I have an understanding that a function is like a struct with two fields: x and y, and those two memory fields are going to be allocated on the stack at the time when function is called.
However, I have no idea at all what is @import and how computer executes it. My level of understanding is just syntactic and shallow.
Moreover, what is a module from computer perspective at all? I suspect, it is a struct, but what does it contain? Why is it a struct? Can it even be something else than a struct?
Does anyone have a good source what I can read to improve on that?
Much obliged!
@import is a primitive to refer to some other source code, it may be a relative file path, or a name that the build system will associate with a module or get a compile error if it doesn’t.
It’s similar to const name = struct{ contents of file/module root file } with the important distinction that the import doesn’t define the struct, the file does, the import is just referring to it the same way you refer to other declarations.
This is an important distinction due to visibility of sub declaration, as the parent namespace of where a type is defined is able to access its sub declarations regardless of visibility, but since @import is only referring to it and the file is defining it separately, that means @import is the boundary where private decls become truly private.
If you didn’t know before, you’d probably be surprised, to learn that files are structs! Types were already namespaces, so zig just reused that concept to avoid making files special. This does mean you can give a file struct fields and instantiate it, just be sure to name the file/module (if it’s the root) with pascal case to communicate that just like you would with any other type.
Unfortunately, due to the struct being implicit for files, you are unable to make a file struct packed or extern or use a different kind of type such as an enum. That would require a sub declaration.
a module is a root source file + all its imports, resulting in a tree of files and other modules. Modules can also include c/c++/asm as well as compiled objects/libraries.
Note that while you do link libraries/objects to a module, you must first create a compile artifact (object/library/executable) if you want to link a module to something else.
Modules for some reason contain a bunch of other configuration that should really be on the compile artifact instead, I expect that to change in the future.
TL;DR: Because in the build.zig file, the executable (or whatever you want to build) declared src/main.zig as root source file. src/root.zig is (with the default build.zig) just a new module which you can import.
The default build.zig file declares a module (which you could call the “root module”) with the root source file being src/root.zig. For all files included in that module (via @import), the @import(“root”) is indeed the src/root.zig file.
But the build.zig file also declares an executable. That executable has a root module (i.e. the module that contains your pub fn main; you would have called it the “main module”), which is often your src/main.zig. All files that are imported by main.zig will have main.zig (or whatever is your module root source file) as @import(“root”).
The module with the root.zig as root source file which has been declared earlier in the build.zig file (if you’re using the build file from zig init) is then added as import to the root module of your main executable. So you have something like the following:
So the root.zig file is not the “root source file” of your program (but it is added as a module which has root.zig as root source file). Instead, main.zig is the “root source file” of your program. Depending on in which module (the “root module” or the “main module” or other modules if you declare them by yourself) the source code is, @import(“root”) references different files.