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

non-exhaustive enums #2524

Closed
daurnimator opened this issue May 20, 2019 · 2 comments · Fixed by #4191
Closed

non-exhaustive enums #2524

daurnimator opened this issue May 20, 2019 · 2 comments · Fixed by #4191
Labels
accepted This proposal is planned. proposal This issue suggests modifications. If it also has the "accepted" label then it is planned.
Milestone

Comments

@daurnimator
Copy link
Contributor

daurnimator commented May 20, 2019

A non-exhaustive enum is an enum that may have other unknown members.
This can help create APIs that may be extended in future. This sort of thing frequently comes up in data formats, network protocols, and even C APIs.

Possible syntax:

  • a non-exhaustive enum is created by including _ as a trailing field.

Semantics:

  • A non-exhaustive enum must have the size specified: enum(u5) { X, Y, Z, _ }
  • If you specify _ when an enum is already "full" (e.g. if it's u2 and you specify 4 values followed by a _), then there is a compiler error.
  • When switch-ed on, an else clause is always required
  • @intToEnum can never fail with has no tag matching integer value
  • builtin.Enum gains a new boolean field is_exhaustive

Related

@daurnimator
Copy link
Contributor Author

#3909 merged some related functionality as a property of extern enums:

  • Non-exhaustive: else prong always needed in switch.
  • @intToEnum can't fail.

@andrewrk
Copy link
Member

andrewrk commented Jan 2, 2020

#3909 made all extern enums non-exhaustive. However, I don't think that should necessarily be how it is. Just because an enum is part of an ABI does not mean it is non-exhaustive. According to how the C ABI works, whether an enum is exhaustive or not is part of the documentation of the API.

So #3909 solved a problem, but it also introduced a problem. And I do think that this proposal solves the new problem.

With this proposal accepted, extern enums can be annotated as exhaustive or non-exhaustive. translate-c will choose non-exhaustive to be safe.

One more part of the specification

  • non-exhaustive enums can be used as the tag type of a tagged union. Every tagged union with a non-exhaustive enum as the tag type would be assumed to have void field types for all unnamed tag values.

I also want to include an extra feature of switch to go along with this proposal. The problem is that when an else is required on a switch, the compile error that tells you about missing tag names is gone. However, programmers should still be able to opt-in to compile errors when new tag names are added to non-exhaustive enums. So I will propose that switch gains _ syntax, which does the following:

  • makes it a compile error if all the known tag names are not handled by the switch
  • allows omitting else

Example:

const E = enum {
    a,
    b,
    _,
};

test "non-exhaustive switch" {
    var e: E = .b;
    switch (e) {
        .a => {},
        .b => {},
        _ => {
            // handle unnamed tag values
        },
        // no else required
        // compile error will occur if another tag is added to E
    }

    switch (e) {
        .a => {},
        .b => {},
        else => {}, // OK; no compile error if another tag is added to E
    }

    switch (e) { // error: switch not handling the tag `b`
        .a => {},
        _ => {},
    }

    switch (e) { // error: switch on non-exhaustive enum must include `else` or `_` prong
        .a => {},
        .b => {},
    }
}

I want to note that there is a case when you would do _ => unreachable. This is when you have a non-exhaustive extern enum because it defines a C ABI, however you know at the switch site that the library will always be linked statically; never dynamically. This means that the value of the enum will never be unnamed, because if the static library was updated, then the zig code would be recompiled against the corresponding updated enum.

Related: #3991

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
accepted This proposal is planned. proposal This issue suggests modifications. If it also has the "accepted" label then it is planned.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants