Why am I getting infinite recursion with ==

Hi


I have the following code, where Suit and CardNumber are enum: Int types:


enum Card: CustomStringConvertible /, Equatable */ {
    case suitCard(Suit, CardNumber)
    case redjoker, blackjoker

   
    static func ==(lhs: Card, rhs: Card) -> Bool
    {
        switch lhs {
        case let .suitCard(lsuit, lnumber):
            switch rhs {
            case let .suitCard(rsuit, rnumber):
                return lsuit == rsuit && lnumber == rnumber
            default: return false
            }
        case .redjoker:
            return rhs == .redjoker
        case .blackjoker:
            return rhs == .redjoker
        }
    }/

}// Card


and when I call:


        if Card.blackjoker == Card.redjoker {
            print("Hello")
        }


it starts going into recursion and blows the stack. It works in most cases, i.e. where the .suitCard option is selected. But on the simple cases, it seems to need some sort of super.== call, but that doesn't work: it encounters an == and calls itself, to find itself back in the same function.


What are we supposed to do at this point?


TIA

Mark

Accepted Reply

Due to the magic of Swift, you can write that revised switch statement more elegantly like this:


static func ==(lhs: Card, rhs: Card) -> Bool
{
     switch (lhs, rhs)
     {
     case (let .suitCard(lsuit, lnumber), let .suitCard(rsuit, rnumber)):
          return lsuit == rsuit && lnumber == rnumber
     case (.redjoker, .redjoker): 
          return true
     case (.blackjoker, .blackjoker):
          return true
     default:
          return false
     }
}

Replies

In

case .redjoker:

return rhs == .redjoker


you call the operator == that you are defining, hence the recursion.


Just write

        switch lhs {
        case let .suitCard(lsuit, lnumber):
            switch rhs {
            case let .suitCard(rsuit, rnumber):
                return lsuit == rsuit && lnumber == rnumber
            default: return false
            }

        case .redjoker:
            switch rhs {
               case  .redjoker : return true
               default : return false
           }


idem with blackJoker

Due to the magic of Swift, you can write that revised switch statement more elegantly like this:


static func ==(lhs: Card, rhs: Card) -> Bool
{
     switch (lhs, rhs)
     {
     case (let .suitCard(lsuit, lnumber), let .suitCard(rsuit, rnumber)):
          return lsuit == rsuit && lnumber == rnumber
     case (.redjoker, .redjoker): 
          return true
     case (.blackjoker, .blackjoker):
          return true
     default:
          return false
     }
}

Much more clean and readable.

Thanks! It is elegant, even if it doesn't say how to reference an inherited ==. I have adopted the tuple switch as you suggestd, it is very readable and clear, and it all works correctly.


Edit: There is no == for the type of enum that has data associated with some values, like this one. So there is no shortcut. But you can use == with enums even without an explicit raw type, as long as there is no data load.

>> how to reference an inherited ==


You can't. In this case, you can't because Card is a value type and there is no inheritance.


For a class (reference) type, you still can't inherit the function because the Equatable protocol requires it to be "static", which implies "final". Therefore this function isn't overridable.


If you wanted to inherit a complicated equality check, the correct way would be to put the code in a regular method in the superclass, and invoke (and/or overrid) this method in the subclass.

If you wanted to inherit a complicated equality check, the correct way would be to put the code in a regular method in the superclass, and invoke (and/or overrid) this method in the subclass.

Note that, if the class is derived from NSObject, such a method already exists, namely,

-isEqual:
.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"