Reviews are an important part of the Swift evolution process. All review feedback should be either on this forum thread or, if you would like to keep your feedback private, directly to the review manager (via email or direct message in the Swift forums).
What goes into a review of a proposal?
The goal of the review process is to improve the proposal under review through constructive criticism and, eventually, determine the direction of Swift.
When reviewing a proposal, here are some questions to consider:
What is your evaluation of the proposal?
Is the problem being addressed significant enough to warrant a change to Swift?
Does this proposal fit well with the feel and direction of Swift?
If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
How much effort did you put into your review? A glance, a quick reading, or an in-depth study?
Is the problem being addressed significant enough to warrant a change to Swift?
Yes
Does this proposal fit well with the feel and direction of Swift?
Yes. I am often reminded that this isn't currently a feature when I try to use it.
How much effort did you put into your review? A glance, a quick reading, or an in-depth study?
I read the proposal and have followed various conversations when it was brought up.
Is the problem being addressed significant enough to warrant a change to Swift?
Not really sure. I have not felt substantial pain around the use of patterns in catch statements but I can vaguely recall a few times I would have used such a capability in the past.
Does this proposal fit well with the feel and direction of Swift?
Yes
If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
Nothing comes to mind.
How much effort did you put into your review? A glance, a quick reading, or an in-depth study?
A quick read of the proposal.
On a quick skim, this makes sense to me. It seems like a straightforward extension of current behavior.
(In hindsight, I kind of wish we’d designed catch differently:
do { ... }
catch {
case TaskError.someRecoverableError:
recover()
case TaskError.someFailure(let msg),
TaskError.anotherFailure(let msg):
showMessage(msg)
// could have a default case, but since we don’t,
// we get one that automatically rethrows
}
But that ship has long since sailed. Oh well, just another entry in REGRETS.md.)
I think it fixes an obvious drawback of do-catch, so +1.
Is the problem being addressed significant enough to warrant a change to Swift?
I think so. Personally I haven't had a need to use this pattern of error handling (there are other ways, such as using Result, etc), but I think it would be a useful addition to the language and can help simplify code in certain scenarios (as mentioned in the proposal).
Does this proposal fit well with the feel and direction of Swift?
Absolutely.
If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
I have used similar functionality in C# (exception filters) long time ago and I think this is comparable to that.
How much effort did you put into your review? A glance, a quick reading, or an in-depth study?
I read the pitch thread, proposal and briefly looked at the implementation code.
macOS (Download Link) and Linux (Download Link) toolchains are now available with the implementation of this feature. If using it with Xcode, I recommend quitting and restarting the app after switching toolchains, otherwise it seems to continue using the older SourceKit for live error messages.
Similar to switch cases, catch clauses with multiple patterns may still contain value bindings. However, those bindings must have the same name and type in each pattern.
As a result, your first example results in a compiler error: error: 'msg' must be bound in every pattern.
Your second example is also invalid code because as is used to write a type-casting pattern, and the right-hand-side, excObject, is not a type.
Just out of curiosity, why wouldn‘t we able to introduce a new syntax form such as you mentioned and slowly fade or not further extend the older one?
If we‘d introduce a switch like catch block then people will start using it and slowly over time the old version will likely go away as all new switch like features would be supported in that new form.
And one more thing, wouldn‘t your catch (switch like) block require a default case at the end?
To wrap up, I would support this proposal as it fits well as an extension of the current functionality. However after reading @beccadax‘s example, I‘m intrigued by this more general syntax form which already would benefit from all switch functionalities that we have today or in the future. So why trying to align something as closely as possible to switches rather than reusing the whole switch case mechanism for do catch?
If there is a chance to go the other way now, I‘d rather choose it and vote my -1 on the current proposed solution.
Under the assumption that we eventually get typed throws, a do catch case would automatically allow us to drop the type prefix from all the patterns. I‘m not sure if this would be the case for the current do catch though, this also depends on how many different try's are in the do block.
I find Switch's pattern matching syntax to be more intuitive and easier to work with so am all for catch to be used in a similar manor.
One question, with the example...
catch TaskError.someRecoverableError { // OK
recover()
}
Is there still an implicit error parameter? Is there any way to access the original error at all and/or rename it?
Basically...
catch TaskError.someRecoverableError {
print(error.localizedDescription) // Is this possible?
// Also what Type would error be? `Error` or `TaskError`?
}
No, this proposal doesn’t change the implicit error binding behavior, which remains only supported in empty catch clauses. This is addressed briefly under alternatives considered. Basically, there are still some open design questions and minor source compatibility issues which need to be resolved before extending the implicit error binding. For example, it might be useful to first introduce the notion of conjunctive patterns like let error as Error @ TaskError.someError, to borrow some syntax from Rust. The error binding could then just be syntactic sugar so users wouldn’t need to write the first part in the common case. Any changes in this area deserve their own dedicated proposal though.