I found myself in a situation where it would be convenient to have an enum be the underlying type for another enum. As far as I can tell, the only previous discussion on that topic was started by me 3 years ago, so that seems to be some type of enduring need for me. I'd like to be able to do something like this:
enum Foo {
case a(Int)
case b(Int, Int)
case z
}
enum Bar : Foo {
case a
case b
}
The idea being that the enumerants of Bar
are a subset of the enumerants of Foo
, just like an enum Foo : Int
is a subset of all the possible Int
s.
Use cases include hierarchies of the kind that LLVM lets you do with its classof
-based RTTI. You declare one large enum that has all the cases that you want to consider related, and you declare smaller enums that group those in related subsets. In a world with typed throws
(has some consensus been reached on that topic? I'm out of the loop), this could be used to declare a large enum of all things that a module can throw, while tailoring smaller error sets for specific functions.
In the above example, Bar
gets the a
and b
cases from Foo
. Their payloads are implicit. No renaming allowed in this feature iteration.
Another strawman possible syntax could be:
enum Bar {
case a(Int)
}
enum Foo {
case z
include Bar
case b(Int, Int)
}
That may seem less backwards because you declare a
once and get it in both enums, but that relationship gravely complicates the story if Bar
can change from under your feet, as Bar
is not allowed to add cases if it comes from another module.
Another syntax could be:
enum Foo {
case z
subgroup Bar {
case a(Int)
}
case b(Int, Int)
}
Here, subgroup
declares a type in the namespace that contains the enclosing enum, and creates the cases in both Foo
and Bar
. Bar
's underlying type is Foo
. On the other hand, that syntax is less powerful than the previous one, as it doesn't allow overlap between subgroups, and it can be implemented on top of one enum that uses the other enum as its underlying type.
Is this something that anyone else would use?