const std = @import("std");
const VTab = struct {
areaFn: *const fn (ptr: *anyopaque) f32,
};
const Circle = struct {
radius: f32,
fn area(self: *anyopaque) f32 {
const s: *const Circle = @ptrCast(@alignCast(self));
return std.math.pi * s.radius * s.radius;
}
pub fn vtable() *const VTab {
return &VTab{ .areaFn = Circle.area };
}
};
const Square = struct {
side: f32,
fn area(self: *anyopaque) f32 {
const s: *const Square = @ptrCast(@alignCast(self));
return s.side * s.side;
}
pub fn vtable() *const VTab {
return &VTab{ .areaFn = Square.area };
}
};
const Shape1 = struct {
ptr: *anyopaque,
vtab: *const VTab,
fn area(self: *Shape1) f32 {
return self.vtab.areaFn(self.ptr);
}
fn init(ptr: *anyopaque, vtab: *const VTab) Shape1 {
return .{
.ptr = ptr,
.vtab = vtab,
};
}
};
pub fn main() !void {
var sq = Square{ .side = 2 };
var cr = Circle{ .radius = 2 };
var shapes = [_]Shape1{
Shape1.init(&sq, Square.vtable()),
Shape1.init(&cr, Circle.vtable()),
};
for (&shapes) |*shape| {
std.log.debug("{d}", .{shape.area()});
}
}
EDIT:
Why this works?
pub fn vtable() *const VTab {
return &VTab{ .areaFn = Square.area };
}
Since the members of VTab are all constant, allocation is static. We get a VTab pointer to the static space that does not change.
Why this does not work?
fn init(ptr: *anyopaque, f: *const fn (ptr: *anyopaque) f32) Shape1 {
return .{
.ptr = ptr,
.vtab = &VTab{ .areaFn = f },
};
}
Here VTab is not constant, f comes in runtime. Since VTab is allocated locally, it is allocated in stack.
When init finishes the stack space is reused by other functions and its value becomes corrupted.
Discussion: Feel confused with lifetime of anonymous struct