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

maybe add functions for directly working with function or struct types #47

Open
lenawanel opened this issue Jul 14, 2024 · 1 comment
Open
Labels
enhancement New feature or request

Comments

@lenawanel
Copy link
Contributor

Problem

currently it is possible to construct struct types at comptime and before, with the

struct { ... };

likewise with functions.
However there is no way to directly work with the struct Type.
Let's say we wanted to add the field a: i32 to some c :: struct { b: i8 }.
Currently that isn't possble afaik, you could only do something similar with
struct { c: c, a: i32 }.
The same thing can be said for functions

Proposed Solution

add some function addfield :: (ty: mut type, field: type) or addfield :: (ty: type, field: type) -> type
also maybe add some iterator/visitor for struct and function types

Notes

No response

@lenawanel lenawanel added the enhancement New feature or request label Jul 14, 2024
@NotAFlyingGoose
Copy link
Member

NotAFlyingGoose commented Jul 16, 2024

Yes, this would be useful.

Although I can't really see a way to make this work without having ty and field be comptime parameters with the current system of how type id's work.

I'm not even sure how this function would be built-in, I don't think codegen crate could really generate any kind of assembly that adds a new Intern<Ty> to the compiler. Maybe if it called a foreign function defined by the compiler and written in Rust? It might also be interesting to go down that route for compile-time edits to the compilation. Like a build.rs but available to every comptime block.

Another possibility, which would allow addfield to not be builtin, would be to have a dedicated syntax for just this scenario,

old :: struct { b: i8 };
new :: struct {
  ..old,
  a: i32,
};

I think Jai had a using keyword, which allowed for multiple-inheritence-esque programming, and something similar to that could be done here.

Although I'm not sure how this might extend to function types.

What do you mean by an iterator/visitor? I had the idea in my head of adding something like rawfn but that was specifically for untyped function pointers. I assume you mean like a new structtype or fntype specifically for representing those kinds of type ids?

Concerning that, the main gripe I have about Zig's comptime and Rust's macros is that the errors all happen at the usage-site, instead of the call-site. This makes it hard to tell which call actually caused the issue, and as a result makes it harder to fix errors. It also makes it hard to see the "true" signature of a function. A function signature should tell what a function actually receives and gives, and if you have to read the body of the function to find out that the ty parameter must be a valid integer type, then the language has failed.

A possible solution might be to allow type to be taken as a compile-time parameter, but you can't make any assumptions at the usage-site on whether it can be used to add or not, or whether it can be given to certain functions, etc.

foo :: (comptime T: type) {
  c: T = 0;
  c = c + 1; // error: T can't be added to T
}

and then you can add a requirement that allows T to be added

// possible syntax
foo :: (comptime T: type impl Number) {
  c: T = 0;
  c = c + 1; // fine
}

foo(i32); // fine
foo(f64); // fine
foo(str); // error!

This system could also be used to ensure that T is a struct/function (if that's what you meant by visitor)

/// `ty` is a compile-time parameter, and must be any kind of struct.
/// `field` is a compile-time parameter, with no restrictions.
addfield :: (comptime ty: type impl Struct, comptime field: type) -> type {
  struct {
    using ty,
    new_field: field,
  }
}

Honestly this really reminds me of dependent types... this whole thing opens a rabbit hole that goes out of the scope of this issue so I'm gonna stop here

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

No branches or pull requests

2 participants