Thank you! This is a really good approach and I will use it, but in my case the code gets very noisy. I have 12 cases and only two of them use 2 different optional variables that need to be unwrapped:
switch (action, foo, bar) {
case ("a", _, _): ...
case ("b", _, _): ...
case ("c", _, _): ...
case ("d", _, _): ...
...
case ("x", let foo?, _): ...
case ("y", _, let bar?): ...
}
So, it would be very handy if it were possible to do where let foo:
switch action {
case "a": ...
case "b": ...
case "c": ...
case "d": ...
...
case "x" where let foo: ...
case "y" where let bar: ...
}
I realize it's not the exact question that you asked, but, if the action value does not absolutely have to be a string, an enum with associated values might make a good choice:
enum Action {
case a, b, c, d
case x(String)
case y(Int)
}
I am guessing that foo and bar are optional in your original code because most actions don't require an additional value, so callers of those actions provide nil, but the other two actions require a value.
If that is the case, an enum with associated values ensures that the actions that require a value have the necessary value, and the other actions don't have to worry about passing nils.
The switch statement ends up very close to what you were originally wanting and since action is an enum and not a string, the compiler can check to make sure every enum case is handled:
switch action {
case .a: ...
case .b: ...
case .c: ...
case .d: ...
...
case .x(let foo): ...
case .y(let bar): ...
}
If foo and bar really could be nil, then the associated value types could be optionals.
Again, I realize what I suggest isn't exactly what you were originally looking to do, but if the type of action is in your control, modeling the actions as an enum with associated values may be a good choice for a variety of reasons.
Infer return for omitted guard body: It has been proposed many times to allow omission of the guard body for the sake of brevity. However, a core principle of Swift is to make control flow explicit and visible. For example, the try keyword exists solely to indicate to the human reader where thrown errors can happen. Implicit returns would violate this principle, favoring terseness over clarity in a way that isn't typical of Swift. Furthermore, there are many ways of exiting the scope other than return (loops may want break or continue ), and not every function has an obvious default value to return.
I see the point and thanks for the link. I think however that maybe in the future it could be reconsidered. It could be applied for example only in very clear scopes, in other ones it could be the compiler to warn the user etc.
In my case, it was literally necessary to process strings with optional parameters. More specifically, I refactored the code a bit regarding parsing deep links. This can be solved in many ways, but in this case I did not complicate the current implementation. I needed to define enum from a string which is a component of a path and query parameters:
enum DeeplinkEvent: Equatable {
case presentPromoCode
// ...
case resetPassword(verificationCode: String)
init?(_ rawValue: String, code: String?) {
switch rawValue:
case "promocode":
self = .presentPromoCode
// ...
case "reset-password" where code != nil:
self = .resetPassword(verificationCode: code!)
default: return nil
}
}