Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Zig things #1

Open
bluesillybeard opened this issue Dec 12, 2023 · 1 comment
Open

Zig things #1

bluesillybeard opened this issue Dec 12, 2023 · 1 comment

Comments

@bluesillybeard
Copy link
Owner

bluesillybeard commented Dec 12, 2023

There are a number of Zig related issues that make development and usage of this library quite difficult.

(Ordered roughly from most important to least important)

Annotating declarations:

In this library, in order to create an instance function that is not dynamically dispatched, the function must be prefixed with 'static_' so the makeInterface function can detect it. A better way to do it without using a prefix does not seem to exist at the moment, although some proposals (such as this one) might make this possible in the future.

Circular Dependencies:

Due to the nature of how interfaces work, there is an extremely annoying tendency to create unavoidable circular dependencies. Some way to break them or at least alleviate them would be appreciated.

Note that I did create a workaround, which can be found in src/tests/circular_reference.zig

A way to detect inferred error sets:

The compiler crashes when trying to use an interface with inferred error sets. The solution is to use a defined error set, but that is not clear to people using this library without knowing that ahead of time. In order to create a better error message than "Oh no the compiler crashed", being able to detect if an error set is inferred would make that a lot better for users.

Creating functions:

Right now, the library still requires the user to create the vtable forward functions (which are used to create the vtable itself, which is part of why there are so many problems with circular dependencies). Some way to generate functions in comptime would be great.

I REALLY don't want to do any preprocessing of the user's code - that would make using this library quite a bit more difficult.

@bluesillybeard bluesillybeard changed the title Replace 'static_' prefix for non-dynamic instance functions Zig things Dec 13, 2023
@bluesillybeard
Copy link
Owner Author

bluesillybeard commented Dec 15, 2023

I spent a few hours thinking of a reasonable way of generating functions in comptime.

Idea of how to create functions in comptime

Previous suggestions would have the comptime code create a string, then compile that using a builtin.
This was not accepted for hopefully clear reasons, however the ability for comptime code to create a function seems very doable considering structs can be created in comptime.

How it would work (from a user's perspective)

This is really two features: declarations in a comptime-generated type, and generating actual functions in comptime.

First up, declarations in a comptime generated type. This is the easier of the two to explain, however it is probably the harder one to implement. A struct can have a list of fields, why not a list declarations? This would simply add a way for a declaration's value and publicity to be given when creating a struct, rather than just its name.

const S = @Type(
    std.builtin.Type{
        .Struct = .{
            // other info is hidden for reasier reading
            .declarations = &[_]std.builtin.Type.Declaration {
                .{
                    .name = "ADeclaration",
                    // The exact way through which the following three fields are filled out does not matter,
                    // Only that a way for the values of declarations can be created by code like this
                    .publicity = .public,
                    .type = comptime_int,
                    .value = 7,
                },
            }
        }
    }
)

test "hello" {
    try testing.expectEqual(7, S.ADeclaration);
}

Next, generating functions in comptime. This is a bit more complex, but still not too bad. Likely easier to implement, because it doesn't require changing a fundamental data structure.

To generate a function, a new builtin, @Fn could be added. It would work similarly to @Type, just instead of returning a type, it returns a function.

It takes a function's type information (std.builtin.Type.Fn) and the implementation of that function.

const std = @import("std");

const my_fn_type = fn(i32) i32;

const my_fn_info = @typeInfo(my_fn_type).Fn;

const myFn = @Fn(my_fn_info, {
    //params is a tuple with all of the parameters
    return args[0] + 20;
})

test "fn" {
    std.testing.expectEqual(120, myFn(100));
}

In the case of this library, it could be used to create the vtable wrapper functions, somewhat similar to this:

// These would be local variables of the function that generates the wrapper functions
const fn_type = fn(Instance, i32) void;

const fn_info = @typeInfo(fn_type).Fn;

const function_name = "dynamicFunction";

const function = @Fn(function_info, {
    // Pretend tuples can be sliced like this. In the real code, one could use an inline-for loop to build the tuple
    const arguments_to_pass = args[1..];
    const vtable_entry = @field(args[0].vtable, function_name);
    @call(.auto, vtable_entry, arguments_to_pass);
});

These two features, when combined, would make it possible to take a list of functions and just straight up build the entire interface type in comptime

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant