12

The following Swift code compiles:

enum GraphDataSource  {
    case array(data: [Double], start: Double?, step: Double?)
    case pairs(XYValues: [Double: Double])
    case pairs(dateValues: [Date: Double])
    case function((Double) -> Double?)

    func localizedName() -> String {
        // TODO: Create localizable strings
        return NSLocalizedString(Mirror(reflecting: self).children.first?.label ?? "", comment: "")
    }
}

It has two enum cases named pairs. But when I try to extract associated value, it turns out that I can't choose the one I want.

    var graphData = GraphDataSource.function(sin)

    switch graphData {
    case .pairs(dateValues: let vals):
        vals.keys.forEach({print($0)})
    case .pairs(XYValues: let xy): // without this case everyting compiles OK
        xy.keys.forEach({print($0)})
    default:
        break
    }

The error is: "Tuple pattern element label 'XYValues' must be 'dateValues'". Is this normal? Feels like compiler should either disallow cases of the same name or allow to switch on both.

2 Answers 2

18

This is a Swift compiler bug. See SR-10077.

Sign up to request clarification or add additional context in comments.

5 Comments

What a relief to know that!
Can you clarify your answer about which part is the bug? Is it the mistaken ability to have two enums with the same name but different associated values or is it the inability to code the switch statement for the two cases?
According to the bug, it is supposed to be legal; the compiler just can't actually do it. I'm not aware of anything in the Swift docs that says whether this should be legal or not.
For people coming by, this issue is still open at the day of comment. Feel free to register on the swift board to watch and up vote this bug. o/
And how many years does Apple need to fix this?
3

There are two workaround to pass different types of associated values throw the one case:

  1. Use Any type for an associated value and then dynamically type check/cast it:
enum DataType {
    case data(_ value: Any)
}

func process(_ type: DataType) {
    switch type {
    case .data(let value):
        if value is Int {
            print("Int value - \(value)")
        }
        else if value is String {
            print("String value - \(value)")
        }
    }
}

process(.data(10)) // Outputs: Int value - 10
process(.data("Text")) // Outputs: String value - Text
  1. Use an additional enum to specify a needed type:
enum ValueType {
    case int(_ value: Int)
    case string(_ value: String)
}

enum DataType {
    case data(_ value: ValueType)
}

func process(_ type: DataType) {
    switch type {
    case .data(let value):
        switch value {
        case .int(let value):
            print("Int value - \(value)")
        case .string(let value):
            print("String value - \(value)")
        }
    }
}

process(.data(.int(10))) // Outputs: Int value - 10
process(.data(.string("Text"))) // Outputs: String value - Text

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.