Interface/Trait

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));
}