This one way of how you’d enforce the existence of certain functions for the concrete types (here Foo
and Bar
) by including them in the compile-time arguments of the interface/trait (here SomeTrait
).
This is probably not the Jai-way to do things…
#import "Basic";
SomeTrait :: struct(
type: Type,
get: (a: type, int) -> int,
set: (a: *type, int, int) -> ()
){}
get :: inline (a: $A/SomeTrait, i: int) -> int {
return a.get(a, i);
}
set :: inline (a: *$A/SomeTrait, i: int, val: int) {
a.set(a, i, val);
}
Foo :: struct {
using _t: SomeTrait(#this, foo_get, foo_set);
data: [4]int;
}
foo_get :: (f: Foo, i: int) -> int {
return f.data[i];
}
foo_set :: (f: *Foo, i: int, val: int) {
f.data[i] = val;
}
Bar :: struct {
using _t: SomeTrait(#this, bar_get, bar_set);
data: [8]int;
}
bar_get :: (b: Bar, i: int) -> int {
return b.data[i] * 2;
}
bar_set :: (b: *Bar, i: int, val: int) {
b.data[i] = -val;
}
do_sth :: (x: *$X/SomeTrait) {
set(x, 0, 12345);
}
main :: () {
f : Foo;
f.set(*f, 1, 42);
print("%\n", f);
print("%\n", f.get(f, 1));
b : Bar;
b.set(*b, 2, 42);
print("%\n", b);
print("%\n", b.get(b, 2));
set(*f, 3, 2021);
set(*b, 3, 2021);
do_sth(*f);
do_sth(*b);
print("%\n", f);
print("%\n", b);
print("%\n", get(f, 3));
print("%\n", get(b, 3));
}