-
-
Notifications
You must be signed in to change notification settings - Fork 3k
Description
This was discussed originally here, and elsewhere :).
Motivation
I've been looking at implementing lambda functions (by first making all functions anonymous) but I feel like I should begin with something a little easier as to help me understand the codebase; I've recently had need for reflection metadata in a codegen which generates getters/setters (amongst other things) for structs in relation to a stack based system for a markup language that translates to a IR/bytecode representation, anyways it would be nice to allow users to disable/hide this generation with a hide tag (as well as customise such as link getters/setters to other functions). Amongst other tags, regardless this would be a nice feature I'm sure many authors would enjoy. I'll be looking towards implementing this, this upcoming weekend but I wanted to gather opinion on syntax :).
Proposal
The original proposal was this;
const Foo = struct {
x: u32 @("anything") @(bar()),
};
fn bar() i32 {
return 1234;
}
However this proposes a problem of how one would access the tags, since they aren't purely the same type; in the majority of cases (specifically I can't think of a case where this isn't true) you just want a string tag not a 'boolean' tag since in reality having something like @(true)
is meaningless compared to @("Hide")
so I propose the following restriction; all tags are just strings and @("X")
is replaced with @tag("X")
this makes it a little simpler to read and a lot simpler to actually handle.
const Foo = struct {
x: u32 @tag("A") @tag("B"),
};
Also tags will be able to be applied to almost anything that is globally scoped that is functions (global), structs (note: variables can't have tags) having something like;
fn X() void @tag("MyFunc") {
...
}
You would access it like;
// For Struct
for (@typeInfo(Foo).Struct.fields) |field| {
for (field.Tags) |tag| {
// Do whatever with tag
}
}
// For function
for (@typeInfo(X).Fn) |tag| {
// Do whatever with tag
}
You could also query all objects that have a certain tag like;
comptime const query = @withTag("A"); // returning typeInfo
Now this would look through each typeInfo available returning a static array of all that have it, however we could also maintain a map of each tag to a list of typeinfo making this much much more efficient but increase the size of the running compiler (I feel a valid tradeoff).
Actual Changes
- Syntax Change: allow
@tag(...)
after types in global 'objects' (functions, structs), currently only@tag(...)
but probably add syntactically support for any attribute (in terms of format@<...>(<...>)
but lexically only support tag, this would allow us to expand it later for other attributes if wanted - Builtin.zig change (autogen that is); add 'tags' field to StructField, and Fn that is a string slice (u8 const)
- Add
@tag(tagName: []const u8)
and@withTag(tagName: []const u8)->[]const @import("builtin").TypeInfo
- Note:
@tag
is not grouped under attributes perhaps but rather is separate as it doesn't have a return type
- Note: