Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Enum with identical cases names with associated values of different types

Tags:

enums

swift

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.

like image 912
Paul B Avatar asked Mar 17 '19 20:03

Paul B


2 Answers

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

like image 143
Rob Napier Avatar answered Sep 23 '22 23:09

Rob Napier


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
like image 30
iUrii Avatar answered Sep 25 '22 23:09

iUrii