[swift-evolution] Draft Proposal: Declare variables in 'case' labels with multiple patterns

Jordan Rose jordan_rose at apple.com
Mon Jan 25 16:15:34 CST 2016


+1 in general, but as a nitpick I think this should be

case let .Case1(x, 2), let .Case2(2, x):

because the patterns really are distinct. (In other words, it seems weird to me that "case let .Case1(x), .Case2(x)" is different from "case .Case2(x), let .Case1(x)".)

Jordan

> On Jan 22, 2016, at 19:39, Andrew Bennett via swift-evolution <swift-evolution at swift.org> wrote:
> 
> Hi,
> 
> I'd like to discuss declaring variables in case labels with multiple patterns. I've written a draft proposal, but I'd like to discuss it first before formally proposing anything.
> 
> https://github.com/therealbnut/swift-evolution/blob/a137202e41588b71d3c0511cff85f82ec5f65629/proposals/0023-declare-variables-in-case-labels-with-multiple-patterns.md <https://github.com/therealbnut/swift-evolution/blob/a137202e41588b71d3c0511cff85f82ec5f65629/proposals/0023-declare-variables-in-case-labels-with-multiple-patterns.md>
> 
> In short:
> 
> switch value {
> case let .Case1(x, 2), .Case2(2, x):
>     print(x)
> }
> 
> The original proposal is here, it may need to adapt after discussion, so I'll try to keep the proposal at that link up-to-date.
> 
> Thanks,
> Andrew
> 
> Declare variables in 'case' labels with multiple patterns
> 
> Proposal: SE-0022 <https://github.com/therealbnut/swift-evolution/blob/master/proposals/0023-declare-variables-in-case-labels-with-multiple-patterns.md>
> Author(s): Andrew Bennett <https://github.com/therealbnut>
> Status: In Discussion
> Review manager: Not In Review
> Introduction
> 
> In Swift 2, it is possible to match multiple patterns in cases. However cases cannot contain multiple patterns if the case declares variables.
> 
> The following code currently produces an error:
> 
> enum MyEnum {
>     case Case1(Int,Float)
>     case Case2(Float,Int)
> }
> switch value {
> case let .Case1(x, 2), .Case2(2, x):
>     print(x)
> case .Case1, .Case2:
>     break
> }
> The error is:
> 
> `case` labels with multiple patterns cannot declare variables. 
> This proposal aims to remove this error when each pattern declares the same variables with the same types.
> 
> Motivation
> 
> This change reduces repeditive code, and therefore reduces mistakes. It's consistent with multi-pattern matching when variables aren't defined.
> 
> Proposed solution
> 
> Allow case labels with multiple patterns to declare patterns by matching variable names in each pattern.
> 
> Using the following enum:
> 
> enum MyEnum {
>     case Case1(Int,Float)
>     case Case2(Float,Int)
> }
> These cases should be possible:
> 
> case let .Case1(x, _), .Case2(_, x):
> case let .Case1(y, x), .Case2(x, y):
> case let .Case1(x), .Case2(x):
> case .Case1(let x, _), .Case2(_, let x):
> Detailed design
> 
> Allow case labels with multiple patterns if the case labels match the following constraints:
> 
> All patterns declare exactly the same variables.
> The same variable has the same type in each pattern.
> Therefore each pattern is able to produce the same variables for the case label.
> 
> Impact on existing code
> 
> This should have no impact on existing code, although it should offer many opportunities for existing code to be simplified.
> 
> Alternatives considered
> 
> Using a closure or inline function
> 
> Code repitition can be reduced with one pattern per 'case' and handling the result with an inline function.
> 
> func handleCases(value: MyEnum, apply: Int -> Int) -> Int {
>     func handleX(x: Int) -> Int {
>         return apply(x) + 1
>     }
>     let out: Int
>     switch value {
>     case .Case1(let x, 2):
>         out = handleX(x)
>     case .Case2(2, let x):
>         out = handleX(x)
>     case .Case1, .Case2:
>         out = -1
>     }
>     return out
> }
> This syntax is much more verbose, makes control flow more confusing, and has the limitations of the what the inline function may capture.
> 
> In the above example apply cannot be @noescape because handleX captures it.
> 
> Also in the above example if out is captured and assigned by handleX then it must be var, not let. This can produce shorter syntax, but is not as safe; out may accidentally be assigned more than once, additionally out also needs to initialized (which may not be possible or desirable).
> 
> Extending the fallthrough syntax
> 
> A similar reduction in code repetition can be achieved if fallthrough allowed variables to be mapped onto the next case, for example:
> 
> switch test {
>     case .Case1(let x, 2): 
>         fallthrough .Case2(_, x)
>     case .Case2(3, .let x):
>         print("x: \(x)")
> }
> This is not as intuitive, is a hack, and fallthrough should probably be discouraged. It is much more flexible, a programmer could adjust the value of x before fallthrough. Flexibility increases the chances of programmer error, perhaps not as much as code-repitition though.
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160125/4197b1d2/attachment.html>


More information about the swift-evolution mailing list