3
class MyClass 
{
    enum MyEnum {
        case FirstCase
        case SecondCase(Int)
        case ThirdCase
    }

    var state:MyEnum!

    func myMethod ()
    {
        if state! == MyEnum.FirstCase {
            // Do something
        }
    }
}

I get the compiler error pointing at the if statement::

Binary operator '==' cannot be applied to two 'MyClass.MyEnum' operands

If instead, I use a switch statement, there is no problem:

switch state! {
    // Also, why do I need `!` if state is already an 
    // implicitly unwrapped optional? Is it because optionals also 
    // are internally enums, and the compiler gets confused?

case .FirstCase:
    // do something...

default:
    // (do nothing)
    break
}

However, the switch statement feels too verbose: I just want to do something for .FirstCase, and nothing otherwise. An if statement makes more sense.

What's going on with enums and == ?

EDIT: This is ultra-weird. After settling for the switch version and moving on to other (totally unrelated) parts of my code, and coming back, the if-statement version (comnparing force-unwrapped property against fixed enum case) is compiling with no errors. I can only conclude that it has something to do with some corrupted cache in the parser that got cleared along the way.

EDIT 2 (Thanks @LeoDabus and @MartinR): It seems that the error appears when I set an associated value to the other enum case (not the one I am comparing against - in this case, .SecondCase). I still don't understand why that triggers this compiler error in particular ("Can't use binary operator '=='..."), or what that means.

9
  • you forgot to initialise state and you are forcing unwrapping it. add guard let state = state else { return } instead Commented Nov 6, 2015 at 6:09
  • This is dummy code with type and variable names changed, and most methods omitted. In my real code, the var is initialized. Either case, that should be a runtime issue at most. In reality, I am testing the value in viewDidLoad(), and the compiler can't know if it is initialized or not. Commented Nov 6, 2015 at 6:15
  • What Xcode version are you using? I don't get this error here Commented Nov 6, 2015 at 6:19
  • 1
    Is that your real code? As Leo said, it compiles without problem in Xcode 7 and 7.1. – Perhaps you have an enum with associated values? Commented Nov 6, 2015 at 6:27
  • 1
    @NicolasMiari: Another option is to make your enum conform to Equatable, as seen here: stackoverflow.com/a/25726677/59541 Commented Nov 6, 2015 at 7:21

2 Answers 2

9

As you said in a comment, your enumeration type actually has associated values. In that case there is no default == operator for the enum type.

But you can use pattern matching even in an if statement (since Swift 2):

class MyClass {
    enum MyEnum {
        case FirstCase
        case SecondCase
        case ThirdCase(Int)
    }

    var state:MyEnum!

    func myMethod () {
        if case .FirstCase? = state {

        }
    }
}

Here .FirstCase? is a shortcut for .Some(MyEnum.FirstCase).

In your switch-statement, state is not automatically unwrapped, even if it is an implicitly unwrapped optional (otherwise you could not match against nil). But the same pattern can be used here:

switch state {
case .FirstCase?:
    // do something...
default:
    break
}

Update: As of Swift 4.1 (Xcode 9.3) the compiler can synthesize conformance to Equatable/Hashable for enums with associated values (if all their types are Equatable/Hashable). It suffices to declare the conformance:

class MyClass {
    enum MyEnum: Equatable {
        case firstCase
        case secondCase
        case thirdCase(Int)
    }

    var state:MyEnum!

    func myMethod () {
        if state  == .firstCase {
            // ...
        }
    }
}
Sign up to request clarification or add additional context in comments.

6 Comments

Thank you very much. I ended up not needing the associated value in my current code, so the if statement works as initially planned, but will remember this pattern for future reference.
@Martin R: Optional(E.A) == E.A // gives me true in Swift 2
@user3441734: Sorry, I don't get what you are asking.
Any way to do this in one line? E.g. let isEqual: Bool = .FirstCase == state
From Swift 4.1 due to SE-0185, Swift also supports synthesizing Equatable and Hashable for enums with associated values.
|
2
class MyClass {
    enum MyEnum {
        case FirstCase
        case SecondCase
        case ThirdCase
    }

    var state: MyEnum!

    func myMethod()  {
        guard let state = state else { return }
        if state == MyEnum.FirstCase {
            // Do something
            print(true)
        } else {
             print(false)
        }
    }
}

let myClass = MyClass()
myClass.state = .FirstCase
myClass.myMethod()
myClass.state = .SecondCase
myClass.myMethod()

3 Comments

What happens if instead of first unwrapping with guard, you skip it and just try to compare state! == MyEnum.FirstCase?
@NicolasMiari your code runs fine here as long as you initialise state property
I repeat: the compiler (static analyzer?) has no way to know if the property is initialized or not at the location where it is used (viewDidLoad), and I am force-unwrapping it (which I souldn't need to, since it is an implicitly unwrapped optional to begin with). And the compiler error I was getting had nothing to do with initialization, but with comparing two enums of the same type (?????)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.