What is the different between @This() and struct?

Hello, guys. So I starting to learn and read zig codebase in github/codeberg. I notice some of the projects/codebase use @This() with PascalCase.zig filenames and some of them are using struct with lowercase.zig filenames. Is there any difference using @This() and struct?

Sorry, if some of you don’t understand my questions. My English is not good and I’m still learning programming. Thanks.

@This() refers to the inner most type

const T = union{
   comptime{
      std.debug.expect(T == @This());
   }
}

All files are implicitly structs, so in the base of a file the inner most type would be a struct

2 Likes

So, as far as I understand, when we use @This() inside a struct, union, etc. It refers to the type/container itself, right? In this case, const T = union { ... }, so @This() refers to that anonymous union.

But what happens when @This() is used outside an explicitly declared struct, union, etc?

For example, I came across this code in zigtools/zls (DiagnosticsCollections.zig):

//! Collects various sources of error messages to be sent out as LSP diagnostics.

const std = @import("std");
const lsp = @import("lsp");
const tracy = @import("tracy");
const offsets = @import("offsets.zig");
const Uri = @import("Uri.zig");

io: std.Io,
allocator: std.mem.Allocator,
mutex: std.Io.Mutex = .init,
tag_set: std.array_hash_map.Auto(Tag, struct {
    version: u32 = 0,
    error_bundle_src_base_path: ?[]const u8 = null,
    error_bundle: std.zig.ErrorBundle = .empty,
    diagnostics_set: Uri.ArrayHashMap(struct {
        arena: std.heap.ArenaAllocator.State = .{},
        diagnostics: []lsp.types.Diagnostic = &.{},
        error_bundle: std.zig.ErrorBundle = .empty,
    }) = .empty,
}) = .empty,
outdated_files: Uri.ArrayHashMap(void) = .empty,
transport: ?*lsp.Transport = null,
offset_encoding: offsets.Encoding = .@"utf-16",

const DiagnosticsCollection = @This();

// The rest of the code...

Here, there is no explicit struct DiagnosticsCollection { ... } surrounding these fields. So what exactly does @This() refer to in this case?

Is the file itself implicitly acting as the struct/container? And if so, why do we define:

const DiagnosticsCollection = @This();

instead of explicitly wrapping everything in a struct like:

const DiagnosticsCollection = struct {
    io: std.Io,
    allocator: std.mem.Allocator,
    // ...
};

I’m trying to understand what is happening under the hood here and why this pattern is used in Zig.

When @This() occurs outside any other container, it refers to the type of the file itself (which is a struct type). Files are always namespaces = containers = struct types.

For files which are instantiable types, like std.Io, this @This() pattern is necessary in order to write methods on that type.

2 Likes

Zig implicitly treats all files as if they are structs

struct {
    //! Collects various sources of error messages to be sent out as LSP diagnostics.
    
    const std = @import("std");
    const lsp = @import("lsp");
    const tracy = @import("tracy");
    const offsets = @import("offsets.zig");
    const Uri = @import("Uri.zig");
    
    io: std.Io,
    allocator: std.mem.Allocator,
    mutex: std.Io.Mutex = .init,
    tag_set: std.array_hash_map.Auto(Tag, struct {
        version: u32 = 0,
        error_bundle_src_base_path: ?[]const u8 = null,
        error_bundle: std.zig.ErrorBundle = .empty,
        diagnostics_set: Uri.ArrayHashMap(struct {
            arena: std.heap.ArenaAllocator.State = .{},
            diagnostics: []lsp.types.Diagnostic = &.{},
            error_bundle: std.zig.ErrorBundle = .empty,
        }) = .empty,
    }) = .empty,
    outdated_files: Uri.ArrayHashMap(void) = .empty,
    transport: ?*lsp.Transport = null,
    offset_encoding: offsets.Encoding = .@"utf-16",
    
    const DiagnosticsCollection = @This();
    
    // The rest of the code...
}