Does the compiler know if a union field is never used?

Let’s say you have a tagged union representing a list of platform-specific application backends:

const Backend = union(enum) {
    wayland: @import("wayland.zig"),
    x11: @import("x11.zig"),
    win32: @import("win32.zig"),
    cocoa: @import("cocoa.zig"),
    // etc.
}

The list is platform-specific, so on most (but not all) platforms only a single option will get set. Attempting to set the wrong field would result in a compile error, as it would import a file that uses external libraries that aren’t available on the target platform.

Is the compiler smart enough to know that a particular field is never used, and avoid importing that file? Or does the use of a union always imply that all code for all fields will get built?

@import isn’t lazy. It always imports, regardless of where it’s declared, because it has to be evaluated at comptime.

Sidenote: the path argument has to be resolved even earlier, at “parsetime”, see this topic.

4 Likes

Very interesting, good to know!

So then, assuming all of the files get imported and comptime-resolved, and then the resulting structs go unused because no code ever references those structs (verifyable at comptime, such as builtin.os.tag), will they be discarded by the compiler?

I know unused functions are discarded, but I don’t know if unused union field structs are, or if the resulting binary will contain platform-specific function calls that will never get called on the target platform, but still had to be linked.

The file structs have to be semantically analyzed to determine the size of the union. I’m not so sure, but I think that in the case of switching on builtin.os.tag only the specific backend’s functions will be analyzed. However, in the case of static dispatch, i.e. when switching with inline else, functions from all backends will be analyzed.

2 Likes