Dumb(?) question about matching enums with associated values

Consider this enum with associated values and the follow on code that wants to check if specific instances of the enum match one of the cases without caring about the associated value

enum Food {
    case cheese(String)
    case tomato(String)
}

let brie = Food.cheese("Brie")
let cheddar = Food.cheese("Cheddar")
let cherryTomato = Food.tomato("Cherry")

if case .cheese = brie {
    print("brie is a cheese")
}
if case .cheese = cheddar {
    print("cheddar is a cheese")
}
if case .cheese = cherryTomato {
    print("cherryTomato is a cheese")
} else {
    print("cherryTomato is not a cheese")
}

This works as expected, producing:

brie is a cheese
cheddar is a cheese
cherryTomato is not a cheese

But I can't find a way to use the same construct in a 'normal' expression. i.e these don't compile:

let brieIsCheese = case .cheese = brie

if !(case .cheese = brie) {}

someFunc(isCheese: case .cheese = brie)

I know that I can add properties to the enum like this:

enum Food {
    case cheese(String)
    case tomato(String)
    
    var isCheese: Bool {
        if case .cheese = self {
            return true
        }
        return false
    }
    
    var isTomato: Bool {
        if case .tomato = self {
            return true
        }
        return false
    }
}

and use those in such tests, but that becomes a pain when there are many individual cases in the enum.

Have I missed a simple solution, or is this another area where swift makes simple concepts really hard.

I recommend using a “helper” enum:

enum Food {
  case cheese(String)
  case tomato(String)
}

extension Food {
  enum Case {
    case cheese
    case tomato
  }
  
  var `case`: Case {
    switch self {
    case .cheese: return .cheese
    case .tomato: return .tomato
    }
  }
}

• • •

However for your particular example, it may be preferable to remove the associated value entirely, and make a struct wrapping a simple enum and string.

This is definitely not a dumb question! The ability to easily match on case identity alone while ignoring associated values has come up a few times on this forum, with suggestions for such syntax as let brieIsCheese = (brie is case .cheese)

6 Likes

@gutley Despite what you said in your post, your problem has nothing to do with associated values. It's clear from your code examples that you're expecting a pattern such as case .cheese = brie to be an expression that produces a boolean value. Thus, you should be able to assign the result of this expression to a variable, or pass it into a function that has a parameter of type Bool. Unfortunately, Swift just doesn't support this behavior (although, I think it should). The same issue exists whether your enum has associated values or not.

It would be much simpler for the existing pattern matching syntax (case .cheese = brie) to also function as an expression that produces a boolean value. Although this wouldn't work when the pattern itself binds variables (value in case .cheese(let value) = brie) because it's not clear what the scope of those variables would be.