Catch a particular enum case and capture whole error value?

Is it possible to catch a particular error enum case and also preserve the entire error value? Example:

enum CookingError: Error {
  case missingIngredient(Ingredient, quantity: Int)
  case kitchenOnFire
}

do {
  try makeFood()
}
catch CookingError.missingIngredient {
  handleMissingIngredient(error)  // This doesn't work, because 'error' isn't defined
}

I've tried the following, and they don't work:


catch let error as CookingError {
  // Not specific enough; I only want to catch missingIngredient errors.
}

catch let error as CookingError.missingIngredient {
  // nope, because an enum case isn't a type
}


catch let error where case CookingError.missingIngredient = error {
  // nope, compiler doesn't like 'case' here
}

The only thing I can think of is to reconstruct the whole error value:

catch CookingError.missingIngredient(let ingredient, let quantity) {
  let error = CookingError.missingIngredient(ingredient, quantity: quantity)
  handleMissingIngredient(error)
}

Is there a better way to do this?

2 Likes

Is handleMissingIngredient immediately destructuring the CookingError internally? If so, what does it do with error values that aren't missingIngredient? And why not just pass the destructured data in directly?

And if handleMissingIngredient doesn't destructure the error internally, does it need to be passed at all?

Okay, you are not going to like this :stuck_out_tongue: but the variant that kind of works:

enum CookingError: Error, Equatable { // <-- added Equatable
    case missingIngredient(Ingredient, quantity: Int)
    case kitchenOnFire
}

do {
    try makeFood()
}
catch let error as CookingError where error != .kitchenOnFire {
    handleMissingIngredient(error)
}

Or, you could define a method in your enum that would allow you to do this:

catch let error as CookingError where error.isMissingIngrediant {
    handleMissingIngredient(error)
}

But it seems like there's nothing else you can do here without making it even uglier.

Does handleMissingIngredient immediately destructuring the CookingError internally?

Yeah, it is destructuring it internally, but then it may also rethrow the error depending on other conditions, so it's nice to have the full error still around.

1 Like

You still can't do what you asked in the thread title, but typed throws helps a lot:

func makeFood() throws(CookingError) { }
do {
  try makeFood()
} catch {
  if case .missingIngredient = error {
    handleMissingIngredient(error)
  }
}