Just found about this library, that cleverly use comptime capabilities and pub usingnamespace to allow interfaces and inheritance as if it was part of the language.
The author have made a video, check it out:
Code from the README
zig
// examples/animals.zig
const std = @import("std");
const interface = @import("interface");
fn AnimalInterface(comptime SelfType: type) type {
return struct {
pub const Self = SelfType;
pub fn speak(self: *const Self) void {
return interface.VirtualCall(self, "speak", .{}, void);
}
pub fn describe(self: *const Self) void {
return interface.VirtualCall(self, "describe", .{}, void);
}
pub fn play(self: *const Self, toy: []const u8) void {
return interface.VirtualCall(self, "play", .{toy}, void);
}
pub fn delete(self: *Self, allocator: std.mem.Allocator) void {
return interface.VirtualCall(self, "delete", .{allocator}, void);
}
};
}
const IAnimal = interface.ConstructInterface(AnimalInterface);
const Animal = struct {
pub usingnamespace interface.DeriveFromBase(IAnimal, Animal);
name: []const u8,
age: u32,
pub fn describe(self: *const Animal) void {
std.debug.print("{s} is {d} years old.\n", .{ self.name, self.age });
}
};
const Dog = struct {
pub usingnamespace interface.DeriveFromBase(Animal, Dog);
base: Animal,
breed: []const u8,
pub fn create(name: []const u8, age: u32, breed: []const u8) Dog {
return Dog{ .base = Animal{
.name = name,
.age = age,
}, .breed = breed };
}
pub fn speak(self: *const Dog) void {
std.debug.print("{s} says: Woof!\n", .{self.base.name});
}
pub fn describe(self: *const Dog) void {
std.debug.print("{s} is {d} years old {s}.\n", .{ self.base.name, self.base.age, self.breed });
}
pub fn play(self: *const Dog, toy: []const u8) void {
std.debug.print("{s} doesn't like: {s}.\n", .{ self.base.name, toy });
}
};
const Cat = struct {
pub usingnamespace interface.DeriveFromBase(Animal, Cat);
base: Animal,
pub fn create(name: []const u8, age: u32) Cat {
return Cat{ .base = Animal{
.name = name,
.age = age,
} };
}
pub fn speak(self: *const Cat) void {
std.debug.print("{s} says: Meow!\n", .{self.base.name});
}
pub fn play(self: *const Cat, toy: []const u8) void {
std.debug.print("{s} plays with {s}.\n", .{ self.base.name, toy });
}
};
pub fn test_animal(animal: IAnimal) void {
animal.describe();
animal.speak();
animal.play("Mouse");
}
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{
.safety = true,
}){};
const allocator = gpa.allocator();
defer _ = gpa.deinit();
var cat = try Cat.create("Garfield", 7).new(allocator);
defer cat.delete(allocator);
var dog = try Dog.create("Lassie", 12, "Rough Collie").new(allocator);
defer dog.delete(allocator);
test_animal(cat);
std.debug.print("\n", .{});
test_animal(dog);
}```
</details>