Swift doesn't call my "==" operator overload when I extend CollectionType

467 Views Asked by At

I have a custom class (VotingOption) which inherits from NSManagedObject and sometimes I want to check if some voting options within an array are duplicates. I am trying to make my code as general as possible. This is what I did to extend the CollectionType protocol:

extension CollectionType where Self.Generator.Element : Equatable {

    var duplicates: [Self.Generator.Element]{
        return = self.filter { element in
            return self.filter { $0 == element }.count != 1
        }
    }

    var hasDuplicates: Bool {
        return (self.duplicates.count != 0)
    }
}

this is working like a charm, except that it is not using the global function:

func ==(lhs: VotingOption, rhs: VotingOption) -> Bool {
     return (lhs.location?.title.lowercaseString == rhs.location?.title.lowercaseString) && (lhs.startDate == rhs.startDate)
}

when I do something like this:

let temp: [VotingOption] = votingOptions?.array as? [VotingOption]
if temp.hasDuplicates {
     //do something
}

When I extend isEqual in VotingOption like this:

class VotingOption: NSManagedObject {

    override func isEqual(object: AnyObject?) -> Bool {

        if let rhs = object as? VotingOption {
            return (self.location?.title.lowercaseString == rhs.location?.title.lowercaseString) && (self.startDate == rhs.startDate)
        } else {
            return false
        }
    }
    ...
    ...
    ... rest of class
}

The app crashes and it points at the AppDelegate with a "libc++abi.dylib: terminating with uncaught exception of type NSException" error

How to tell the "==" in CollectionType to use the global function of VotingOption?

2

There are 2 best solutions below

0
On BEST ANSWER

Thanks for all those who helped. I will post final implementation here: Basically created a new protocol "Identity" with a method "equals" which is basically "==" and finally added a generic extension for NSManagedObjects that implement "Identity" which basically does "==" in the "equals" method. However in "VotingOption" I have overrided this function for my specific needs. Finally, the collection type was extended where the "Element" is "Identity". instead of "==" it calls the "equals" method :)

protocol Identity {
     func equals(rhs: Self) -> Bool
}

extension Identity where Self: NSManagedObject {
     func equals(rhs: Self) -> Bool {
          return self == rhs
     }
}

extension CollectionType where Self.Generator.Element : Identity {

    var duplicates: [Self.Generator.Element] {

        return self.filter { element in
            return self.filter { $0.equals(element) }.count != 1
        }
    }

    var hasDuplicates: Bool {
        return (self.duplicates.count > 0)
    }
}

class VotingOption: NSManagedObject, Identity {

    func equals(rhs: VotingOption) -> Bool {

    //... implementation here
    }
}
1
On

Here's a solution that implements the duplicates and hasDuplicates twice, once for Equatable elements, and once for your VotingOptions class. In order to reduce code duplication as much as possible, I've defined a generic implementation for finding duplicates that allows you to pass a function/closure that compares the two elements:

extension CollectionType {

    func findDuplicates(checkEqual: (Self.Generator.Element, Self.Generator.Element) -> Bool) -> [Self.Generator.Element]{
        return self.filter { element in
            return self.filter { checkEqual($0, element) }.count != 1
        }
    }
}

extension CollectionType where Self.Generator.Element : Equatable {

    var duplicates: [Self.Generator.Element]{
        return self.findDuplicates(==)
    }

    var hasDuplicates: Bool {
        return (self.duplicates.count != 0)
    }
}

extension CollectionType where Self.Generator.Element : VotingOption {

    var duplicates: [Self.Generator.Element]{
        return self.findDuplicates {lhs, rhs in
            return (lhs.location?.title.lowercaseString == rhs.location?.title.lowercaseString) && (lhs.startDate == rhs.startDate)
        }
    }

    var hasDuplicates: Bool {
        return (self.duplicates.count != 0)
    }
}