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

Andrew Bennett cacoyi at gmail.com
Fri Jan 22 21:39:23 CST 2016


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.


In short:

switch value {
case let .Case1(x, 2), .Case2(2, 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.


Declare variables in 'case' labels with multiple patterns

   - Proposal: SE-0022
   - Author(s): Andrew Bennett <https://github.com/therealbnut>
   - Status: *In Discussion*
   - Review manager: *Not In Review*


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):
case .Case1, .Case2:

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.


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
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.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160123/bce62656/attachment.html>

More information about the swift-evolution mailing list