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 catch
es 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?