0
votes

I would like to figure out how to pattern match against an enum-with-associated-value property of an error type in a catch. Everything works as expected with an enum without associated values, but I can't seem to figure out the correct pattern for this situation.

struct MyError: Error {
    enum Size {
        case big, small
    }

    enum Solution {
        case runAway
        case other(String)
    }

    let size: Size
    let solution: Solution
}

func action() {
    do {
        // ...
    }
    catch let error as MyError where error.size == .big {
        // This works fine, as `size` has no associated values.
    }
    catch let error as MyError where error.solution == .other {
        // I want to handle all cases of `Solution.other` here, regardless of the associated value.
    }
    catch {
       // ...
    } 
}

The second catch pattern won't compile (as expected due to the enum with associated value). The usual way I'd accomplish this would be a if case .runAway = error.solution {...}, but integrating this in the catch pattern is the problem.

I tried many combinations of if case/let case/case let, but couldn't get this working in a single catch pattern matching statement. This feels like it should be possible given the power and flexibility of pattern matching, so I'm hoping I've just overlooked something.

Thanks for the assistance!

2

2 Answers

1
votes

This feels possible, but isn't :/. What you are trying to use is an enum case pattern. According to here, an enum case pattern is only allowed in switch, if, while, guard, and for statements.

You can add an isOther property in Solution:

var isOther: Bool {
    if case .other = self {
        return true
    } else {
        return false
    }
}

And then use it in the catch:

do {
    // ...
}
catch let error as MyError where error.size == .big {
    // ...
}
catch let error as MyError where error.solution.isOther {
    // ...
}
catch {
   // ...
} 
0
votes

There are 2 things which should be fixed in your sample:

  1. To compare cases of an enum it should be equitable, isn't it? For such a simple enum just mark Solution as Equitable.

  2. Default case for a catch isn't handled, so you need to add it, eg:

    do { ... } catch let error as MyError where error.size == .big { // This works fine, assizehas no associated values. } catch let error as MyError where error.solution == .runAway { // I want to accomplish this comparison. } catch let error { ... }