This is a probably stupid idea, but here goes… .
What I’m suggesting has 2 parts:
Part 1 (old syntax)
Instead of having default unknown or unknown case cases, have that kind of switch throw a unique type of error, say (for the sake of explicitness, it doesn't matter what the name is) UnknownCaseError. That’s the entire behavior, except for one small dollop of special sauce: the compiler knows that the switch statement (separate from what errors its contained statements can throw) can throw no other kind of error. That means this:
do {
try switch excuse {
case .eatenByPet:
…
case .thoughtItWasDueNextWeek:
…
}
catch is UnknownCaseError {
…
}
has an exhaustive catch, so works fine in an enclosing non-catching scope.
Part 2 (new syntax)
Then, make the switch itself a catching scope, if it needs to be (that is, if it would have needed default unknown or unknown case under the existing proposal), but with a simpler syntax. The above example would be written more simply like this:
try switch excuse {
case .eatenByPet:
…
case .thoughtItWasDueNextWeek:
…
catch is UnknownCaseError:
…
}
This means that an UnknownCaseError could be thrown at any level of enum non-exhaustion, and be caught at any higher level of switch. Rewriting earlier examples:
switch (excuse, notifiedTeacherBeforeDeadline) {
case (.eatenByPet, false):
// 1
case (_, false):
// 2
case (let excuse, true):
try switch excuse {
case .eatenByPet: // 3
case .thoughtItWasDueNextWeek: // 4
catch is UnknownCaseError: // 5
}
}
or:
try switch (excuse, notifiedTeacherBeforeDeadline) {
case (.eatenByPet, false):
// 1
case (_, false):
// 2
case (let excuse, true):
switch excuse {
case .eatenByPet: // 3
case .thoughtItWasDueNextWeek: // 4
}
catch is UnknownCaseError: // 5
}
or:
try switch (excuse, notifiedTeacherBeforeDeadline) {
case (.eatenByPet, false):
// 1
case (_, false):
// 2
case (.eatenByPet, true):
// 3
case (.thoughtItWasDueNextWeek, true):
// 4
catch is UnknownCaseError:
// 5
}
This borrows, approximately, the known semantics of catching nested errors to clarify what it means to have such special catches at various levels.
The idea here is that any other “normal” errors thrown inside the try switch would slip past this catch is UnknownCaseError . And vice versa: any additional catch cases would catch matching errors in the obvious way:
try switch (excuse, notifiedTeacherBeforeDeadline) {
case (.eatenByPet, false):
// 1
case (_, false):
// 2
case (.eatenByPet, true):
// 3
case (.thoughtItWasDueNextWeek, true):
// 4
catch is UnknownCaseError:
// 5
catch SchoolError.retiredTeacherError:
print (“Saved by the bell!”)
catch:
print (“Explanation was rejected: \(error)”)
}
No doubt there’s lots wrong with this idea, but the discussion in this thread does seem to be trying to “reinvent” catching errors as a case, so why not just allow it?