Traits for Static Dispatch

This method is something I never thought of before. It’s great! If we adopt this approach, we don’t even need to introduce |T| grammar.

You can take a look at this example:

const std = @import("std");

pub fn satisfyTrait(comptime Trait: type, comptime T: type) R: {
    if (@typeInfo(Trait) != .@"struct")
        @compileError("Trait must be an 'struct'.");
    break :R bool;
} {
    const decls = std.meta.declarations(Trait);
    inline for (decls) |decl| {
        if (!std.meta.hasMethod(T, decl.name)) {
            return false;
        }
    }
    return true;
}

pub const Drawable = struct {
    pub fn draw(self: *const Drawable) void {
        _ = self;
        @compileError("No impl");
    }
};

pub fn draw(drawable: anytype) R: {
    if (!satisfyTrait(Drawable, @TypeOf(drawable)))
        @compileError("drawable must satisfy Drawable trait");
    break :R void;
} {
    drawable.draw();
}

pub const Circle = struct {
    radius: f32,

    pub fn draw(self: *const Circle) void {
        std.debug.print("Circle(radius={})", .{self.radius});
    }
};

pub fn main(init: std.process.Init) !void {
    _ = init;
    const circle = Circle{ .radius = 5.0 };
    draw(circle);
}

I can completely decide on the logic of satisfyTrait. Even imitating the logic of Rust.

The purpose of all the methods I proposed is that when I call third-party libraries, I am not sure what the library author expects when using anytype here, so I hope to introduce a mechanism to inform me of its limitations. When writing restrictions as Zig code in the return type expression, I can directly see what type of value I should pass in through the IDE’s hover prompt. This must be one of the best encoding methods for Zig!!!

I only implemented a simple satisfyTrait above, and I expect the standard library to have a complete satisfyTrait. It not only checks whether the declaration exists, but also whether the declared type matches.

THIS IDEA IS REALLY GREAT!!!

1 Like