Is it useful for std.enums.valuesFromFields and std.enums.values to return slices instead of pointers to arrays?

Hi! Just a little discussion question about standard library functions.

I have been using the std.meta.tags function to iterate over enums—which works nicely, so I guess there is no need to change—BUT, I’ve only recently learned of the existence of std.enums.values and, consequently, std.enums.valuesFromFields.

At a first glance (while speaking strictly only about enums) std.meta.tags and std.enums.values do bascially the same thing – return all values of the enum, correctly typed. However, there is an important difference, that being that std.meta.tags returns a pointer to an array of enum values, while std.enums.values* return a slice of enum values. This might seem inconsequential, but there is an important difference – the former’s .len is of type comptime_int, while the latter’s .len is of type usize. This means the two functions are not drop-in interchangeable. In my codebase, swapping std.meta.tags for std.enums.values leads to compile errors, because I’m using the .len value for some calculations with u32 values, so I would need to add extra @intCasts.

Now, is there any advantage to the std.enums.values* functions having the slice return type? Since both lengths are always comptime-known, I would argue it would make sense for them to return array pointers, just like std.meta.tags already does. On that note, is there even a reason for std.enums.values to exist separately from std.meta.tags?

1 Like

Hey, welcome to Ziggit!

The only difference between std.meta.tags() and std.enums.values() (besides their return type) seems to be that the former uses @enumFromInt() and the latter @field to populate the result.

Looking at the git blame that’s probably because of this:

But this isn’t relevant anymore because fields and decls cannot share names since 0.14.0:

So I don’t think there is a reason for std.enums.values() to exist anymore.

I guess there is a case to be made for std.enums.valuesFromFields() though. Although the only usage of this function is inside std.enums:

Also *const [n]T coerces to a slice anyway so it should always be preferred IMO.

1 Like

That definitely sounds useful. Though, if I’m not mistaken, the return type of that could easily be changed to *const [fields.len]E, no?

1 Like

Yeah definitely, I think this would be a good change. Although I’m not really convinced whether std.enums.valuesFromFields() is very useful…

1 Like

I’m thinking something like iterating over the common values of an enum and its subset might be useful?

const A = enum { a, b, c, d };
const B = enum { b, d };

for (std.enums.valuesFromFields(A, std.meta.fields(B))) |a| {
    // ...
}

I don’t have a more concrete use-case right now, though.

2 Likes

I’ve opened an issue about this:

This probably doesn’t do what you think it does (see the issue)

1 Like

Oh, funny. The function’s doc comment is wrong then, because it says that the function only uses names and ignores values, but the actual code uses values instead of names.

1 Like