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

make @tagName of non-exhaustive enums return an optional #12845

Open
andrewrk opened this issue Sep 14, 2022 · 5 comments
Open

make @tagName of non-exhaustive enums return an optional #12845

andrewrk opened this issue Sep 14, 2022 · 5 comments
Labels
breaking Implementing this issue could cause existing code to no longer compile or have different behavior. proposal This issue suggests modifications. If it also has the "accepted" label then it is planned.
Milestone

Comments

@andrewrk
Copy link
Member

Extracted from #7320.

Currently, @tagName for a non-exhaustive enum asserts that the integer has a corresponding tag name:

const std = @import("std");

const E = enum(u32) {
    one,
    two,
    _,
};

pub fn main() !void {
    var e1: E = .two;
    var e2: E = @intToEnum(E, 99);
    std.debug.print("{s}, {s}\n", .{ @tagName(e1), @tagName(e2) });
}
thread 1769982 panic: invalid enum value
./test.zig:12:20: 0x20d39b in main (test)
    std.debug.print("{s}, {s}\n", .{ @tagName(e1), @tagName(e2) });
                   ^
/home/andy/dev/zig/lib/std/start.zig:578:37: 0x20d0f0 in posixCallMainAndExit (test)
            const result = root.main() catch |err| {
                                    ^
/home/andy/dev/zig/lib/std/start.zig:340:5: 0x20cad2 in _start (test)
    @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
    ^
Aborted (core dumped)

This proposal is to change @tagName to return an optional in this case. Previous behavior can be obtained by adding .? to the end of the @tagName call.

The compile errors at each @tagName callsite that would be introduced when changing an enum to and from a non-exhaustive enum are helpful and desirable.

@andrewrk andrewrk added breaking Implementing this issue could cause existing code to no longer compile or have different behavior. proposal This issue suggests modifications. If it also has the "accepted" label then it is planned. labels Sep 14, 2022
@andrewrk andrewrk added this to the 0.11.0 milestone Sep 14, 2022
@marler8997
Copy link
Contributor

If possible, it would be nice to include the "big O" complexity for calling @tagName on non-exhaustive enums. Is this going to be done with a map O(1) or something like a binary search O(log(N))? This is assuming the worst case where values are sparse, a simple array will have O(1) for contiguous values. I'd love to see a perfect hash implementation in the compiler for things like this :)

@InKryption
Copy link
Contributor

If this has any chance of being accepted, how about being able to handle invalid type coercion in @TypeOf? Often I find some generic code where it would be beneficial to figure out whether two types will coerce, but want a separate branch for if they don't. Could we have @TypeOf return an optional, if it is given more than one argument?

@nektro
Copy link
Contributor

nektro commented Sep 15, 2022

@marler8997 std.ComptimeStringMap chooses a different strategy based on size

@InKryption that should be its own issue

@andrewrk andrewrk modified the milestones: 0.11.0, 0.12.0 Apr 9, 2023
@ifreund
Copy link
Member

ifreund commented May 2, 2023

Note that with the existence of inline switch cases, accepting #12250 would allow implementing this behavior fairly concisely in userland with

switch (foo) {
    _ => null,
    inline else => |f| @tagName(f),
}

@InKryption
Copy link
Contributor

With #12250 you wouldn't need the inline there either. Just else => |tag| @tagName(tag) would ought to work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking Implementing this issue could cause existing code to no longer compile or have different behavior. proposal This issue suggests modifications. If it also has the "accepted" label then it is planned.
Projects
None yet
Development

No branches or pull requests

5 participants