Consider the hypothetical scenario where a CasePath<Enum, Value>
and PartialCasePath<Enum>
had been introduced to the language, and SE-0914 came along with both CaseIterable
and CasePathIterable
.
If we look at it from this perspective, we can find a pretty convincing argument for case paths to be first class citizens in the language, as they're in fact the equivalent of supercharged enum discriminators!
Synthesized enum discriminators are one of the most requested features for enums, second only to extracting payloads from enum cases more easily. Both of these problems are solved in the same way: by introducing a way to refer to the discriminator of an enum case and operate with it, aka being able to refer to a "Case Path".
In the case of CasePathIterable
, you'd get something like:
enum Foo: CasePathIterable {
case a, b, c
// synthesized
static var allCasePaths: [CasePath<Bar, Void>] // contains \Foo.a?, \Foo.b?, and \Foo.c?, which actually act as discriminators!
// equivalent to:
enum Discriminator: CaseIterable {
case a, b, c
}
static var allDiscriminators: [Discriminator] // contains Discriminator.a, Discriminator.b, Discriminator.c
}
enum Bar: CasePathIterable {
case a(String)
case b(Int)
case c(URL?)
// synthesized
static var allCasePaths: [PartialCasePath<Bar>] // contains \Bar.a?, \Bar.b?, and \Bar.c?, which actually act as discriminators!
// equivalent to:
enum Discriminator: CaseIterable {
case a, b, c
}
static var allDiscriminators: [Discriminator] // contains Discriminator.a, Discriminator.b, Discriminator.c
}
CasePath
and PartialCasePath
could even be made exhaustively switchable at compiler level since they refer to a specific enum type, so there's always a finite amount of known paths for a given Root
type.
As you can see, these are not part of an opt-in protocol, these are first class citizens leveraged by the better opt-in protocol: CasePathIterable
.