1

I have an enum similar to this, where all cases contain the same associated value content:

enum RowType {
    case single(_ content: [Any])
    case double(_ content: [Any])
    case triple(_ content: [Any])
    ...
}

I know I could just use a struct with a rowType and a content attribute, but let's please not discuss this, but rather have a look at the following: When I want to switch all the cases, I could of course do this:

switch row {
case .single(let content):
    // do anything
    break
case .double(let content):
    // ...
...
}

or even:

switch row {
case .single(let content), .double(let content), ...:
    // do the same thing for all cases
    break
}

Now my enum contains a few more cases and is likely to grow further while under development, so it's inconvenient for me to list all cases in the same case statement just to unwrap the content argument.

So I got curious and wondered: Can I somehow "wildcard" the enum case itself and still unwrap the content field? Like a default case with associated value...

I was hoping to be able to do something like ...

switch row {
case _(let content):
    // do something
    break
}

... or maybe accessing the associated value in the default case.

I did a bit of research but couldn't find an answer, so I'm excited for your thoughts.

emmics
  • 994
  • 1
  • 11
  • 29
  • 2
    Such a feature does not exist. Using a struct with a rowType and a content attribute instead would be the correct approach. – Martin R Aug 15 '19 at 08:11
  • 1
    A possible solution is to add a computed property to your enum that contains a switch that then returns your. content. You still need to include all possibilities but only once. – Michael Salmon Aug 15 '19 at 08:52
  • It's not possible right now, even because every case could contain different kind of associated values (or not having at all) and the compiler wouldn't be able to handle all of them with a single wildcard – Rico Crescenzio Aug 15 '19 at 09:47
  • @MichaelSalmon ah well that's actually a great idea! Thanks for sharing! – emmics Aug 16 '19 at 04:55
  • @RicoCrescenzio yes it _could_, but can't I tell him to rely on that, something like force unwrapping the enum value? Something like a case for "Whenever I can unwrap an associated value with type `[Any]` ". I mean, it's still a switch which provides a default clause as a fallback... Do you know what I mean? – emmics Aug 16 '19 at 04:58

1 Answers1

1

Try this in Playground.

enum RowType {
case single(_ content: [Any])
case double(_ content: [Any])
case triple(_ content: [Any])
case noVal

var associatedValue: Any? {
    get {
        let mirror = Mirror(reflecting: self)
        if let associated = mirror.children.first {
            return  associated.value
        }
        print("WARNING: Enum option of \(self) does not have an associated value")
        return  nil
    }
  }
}

let row : RowType = .double([1,2,3])
let rowNoVal : RowType = .noVal
row.associatedValue
rowNoVal.associatedValue
Paul B
  • 3,989
  • 33
  • 46
  • Works pretty fine actually, thanks for sharing! Can you think of a "safer" variant, for example without Mirror? – emmics Nov 11 '19 at 11:47
  • I was searching for the safer variant without Mirror, @Muli. (You can see that by my Q&A here.) Here is one of attempts to do that https://stackoverflow.com/questions/55212028/enum-with-associated-value-conforming-to-caseiterable-rawrepresentable Note that in static cases rawValues can do the job instead. – Paul B Nov 12 '19 at 08:30
  • 1
    Otherwise I can only think of such a straightforward solution, @Muli: `var associatedValue: Any? { get { switch self { case .single(let content), .double(let content), .triple(let content): return content default: return nil } } } }` – Paul B Nov 12 '19 at 08:51
  • Yup, looks nice! Also your straightforward solution seems like a nice workaround. Thank you – emmics Nov 14 '19 at 07:53