Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SR-9331] NSMutableSet uses identity check instead of equality upon adding Swift class #51801

swift-ci opened this issue Nov 24, 2018 · 2 comments


Copy link

@swift-ci swift-ci commented Nov 24, 2018

Previous ID SR-9331
Radar None
Original Reporter ifndefgt (JIRA User)
Type Bug

Checked with both

Apple Swift version 4.0.3 (swiftlang-900.0.74.1 clang-900.0.39.2)

Target: x86_64-apple-macosx10.9


Apple Swift version 4.2.1 (swiftlang-1000.11.42 clang-1000.11.45.1)

Target: x86_64-apple-darwin17.7.0

Additional Detail from JIRA
Votes 0
Component/s Standard Library
Labels Bug, Runtime
Assignee None
Priority Medium

md5: ff3f6afba9d8cb7ef2090342fe90af70

Issue Description:

I have a Swift class below. When I insert its 2 equal instances into a Swift Set upon insertion Hashable protocol implementation is used as expected. However when I insert the same instances into NSMutableSet none of the implementations (Hashable or NSObjectProtocol methods) are used.

When I disassemble the code, as I see _SwiftObject_hash method is called. But it just returns object address, so identity is used for duplicate checking.

When I change the class type to a Swift struct or a class that inherits NSObject everything works as expected.

I'm not sure if this is expected behavior. But if it's that's really confusing. It caused a bug in my project and cost me one day of debugging, trying alternatives etc. After searching for a while I couldn't find any resource referencing this behavior, so here is a bug report.

class Model: Hashable {
    let name: String
    let number: Int
    init(name: String, number: Int) { = name
        self.number = number
    static func ===(lhs: Model, rhs: Model) -> Bool {
        return ( ==
            && (lhs.number == rhs.number)
     static func ==(lhs: Model, rhs: Model) -> Bool {
        return ( ==
            && (lhs.number == rhs.number)
    var hashValue: Int {
        return name.hashValue << 1 &+ number
    var hash: Int {
        return name.hashValue << 1 &+ number
    func isEqual(_ object: Any?) -> Bool {
        guard let object = object as? Model else {
            return false
        return ( ==
            && (self.number == object.number)
    func isEqual(_ object: AnyObject?) -> Bool {
        guard let object = object as? Model else {
            return false
        return ( ==
            && (self.number == object.number)


var swiftSet = Set<Model>()
var nextStepSet = NSMutableSet()
let name = "Gokhan Topcu"
let model1 = Model(name: name, number: name.count)
let model2 = Model(name: name, number: name.count)
print(swiftSet.count) // prints 1
print(nextStepSet.count) // prints 2
Copy link

@belkadan belkadan commented Nov 26, 2018

cc @jckarter, @mikeash. I think we just never finished the SwiftObject/Hashable implementation…

Copy link

@mikeash mikeash commented Nov 26, 2018

- (NSUInteger)hash {
return (NSUInteger)self;

- (BOOL)isEqual:(id)object {
return self == object;


@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
None yet

No branches or pull requests

3 participants