[swift-users] odd `==` `!=` behavior with class that inherits `NSObject`

Nate Birkholz nbirkholz at gmail.com
Tue Apr 18 22:31:17 CDT 2017


I'm not sure exactly how class declarations interact with the scope of a
do{ } statement. I declare a new static function inside your do{ } scope
and it works fine, but something about the mapping of `==` and `!=` to
`isEqual` in NSObject seems to be confused by the scope of the do{ } block.

I'm not sure what the use case is for declaring a class inside a do{ }
block, but it seems like a bug with SNObject operator mapping:

//: Playground - noun: a place where people can play


import UIKit


do{

class Foo:NSObject {

    let name:String


    init(name:String) {

        self.name = name

    }


    public static func testStatic(_ object: Foo) {

        print(object.name)

    }


    public static func ==(lhs: Foo, rhs: Foo) -> Bool {

        guard type(of:lhs) == type(of:rhs) else { return false }

        return lhs.name == rhs.name

    }


    public static func !=(lhs: Foo, rhs: Foo) -> Bool {

        guard type(of:lhs) == type(of:rhs) else { return false }

        return lhs.name != rhs.name

    }


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

        print("in isEqual")

        guard let object = object as? Foo else { return false }

        let _ = super.isEqual(object)

        if self.name == object.name {

            return true

        }


        return false

    }

}


    let a = Foo(name: "bar")

    let b = Foo(name: "bar")


    print(a == b) // true

    print(a != b) // false


    Foo.testStatic(a) // bar

}


output is:

in isEqual

true

in isEqual

false

bar


For the record, enclosing just the statements *outside* the class
declaration in a do{ } block works as expected:

class Foo:NSObject {

    let name:String


    init(name:String) {

        self.name = name

    }


    public static func ==(lhs: Foo, rhs: Foo) -> Bool {

        guard type(of:lhs) == type(of:rhs) else { return false }

        return lhs.name == rhs.name

    }


    public static func !=(lhs: Foo, rhs: Foo) -> Bool {

        guard type(of:lhs) == type(of:rhs) else { return false }

        return lhs.name != rhs.name

    }


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

        print("in isEqual")

        guard let object = object as? Foo else { return false }

        let _ = super.isEqual(object)

        if self.name == object.name {

            return true

        }


        return false

    }

}

do{

    let a = Foo(name: "bar")

    let b = Foo(name: "bar")


    print(a == b) // true

    print(a != b) // false

}


output:

true

false


On Tue, Apr 18, 2017 at 8:07 PM, Zhao Xin <owenzx at gmail.com> wrote:

> Just put your code in to a do-block. The result will be opposite.
>
>
> do {
>
>
>
>     class Foo:NSObject {
>
>         let name:String
>
>
>
>         init(name:String) {
>
>             self.name = name
>
>         }
>
>
>
>         public static func ==(lhs: Foo, rhs: Foo) -> Bool {
>
>             guard type(of:lhs) == type(of:rhs) else { return false }
>
>             return lhs.name == rhs.name
>
>         }
>
>
>
>         public static func !=(lhs: Foo, rhs: Foo) -> Bool {
>
>             guard type(of:lhs) == type(of:rhs) else { return false }
>
>             return lhs.name != rhs.name
>
>         }
>
>     }
>
>
>
>     let a = Foo(name: "bar")
>
>     let b = Foo(name: "bar")
>
>
>
>     print(a == b) // true, now false
>
>     print(a != b) // false, now true
>
> }
>
>
> Zhaoxin
>
> On Wed, Apr 19, 2017 at 11:04 AM, Nate Birkholz <nbirkholz at gmail.com>
> wrote:
>
>> Your issue seems to be that you created a custom implementation for the
>> `==` operator but not one for the `!=` operator. If I add a custom
>> implementation for `!=` I get the results you expected. Tthe default
>> implementation of NSObject's `isEqual` is a test for identity, like the
>> `===` in Swift. So when you ask "is `a` NOT the same object in memory as
>> `b`?" the object returns "true" because they are indeed not the same object.
>>
>> class Foo:NSObject {
>>
>>     let name:String
>>
>>
>>     init(name:String) {
>>
>>         self.name = name
>>
>>     }
>>
>>
>>     public static func ==(lhs: Foo, rhs: Foo) -> Bool {
>>
>>         guard type(of:lhs) == type(of:rhs) else { return false }
>>
>>         return lhs.name == rhs.name
>>
>>     }
>>
>>
>>     public static func !=(lhs: Foo, rhs: Foo) -> Bool {
>>
>>         guard type(of:lhs) == type(of:rhs) else { return false }
>>
>>         return lhs.name != rhs.name
>>
>>     }
>>
>> }
>>
>>
>> let a = Foo(name: "bar")
>>
>> let b = Foo(name: "bar")
>>
>>
>> print(a == b) // true
>>
>> print(a != b) // false
>>
>> On Tue, Apr 18, 2017 at 7:33 PM, Zhao Xin via swift-users <
>> swift-users at swift.org> wrote:
>>
>>> Sample 1: both `==` and `!=` is true.
>>>
>>> import Foundation
>>>
>>>
>>> class Foo:NSObject {
>>>
>>>     let name:String
>>>
>>>
>>>     init(name:String) {
>>>
>>>         self.name = name
>>>
>>>     }
>>>
>>>
>>>     public static func ==(lhs: Foo, rhs: Foo) -> Bool {
>>>
>>>         guard type(of:lhs) == type(of:rhs) else { return false }
>>>
>>>         return lhs.name == rhs.name
>>>
>>>     }
>>>
>>> }
>>>
>>>
>>> let a = Foo(name: "bar")
>>>
>>> let b = Foo(name: "bar")
>>>
>>>
>>> print(a == b) // true
>>>
>>> print(a != b) // true
>>>
>>> Sample 2: Add above code to a do-block, behavior changes to expect
>>>
>>> do {
>>>
>>>     class Foo:NSObject {
>>>
>>>         let name:String
>>>
>>>
>>>
>>>         init(name:String) {
>>>
>>>             self.name = name
>>>
>>>         }
>>>
>>>
>>>
>>>         public static func ==(lhs: Foo, rhs: Foo) -> Bool {
>>>
>>>             guard type(of:lhs) == type(of:rhs) else { return false }
>>>
>>>             return lhs.name == rhs.name
>>>
>>>         }
>>>
>>>     }
>>>
>>>
>>>
>>>     let a = Foo(name: "bar")
>>>
>>>     let b = Foo(name: "bar")
>>>
>>>
>>>
>>>     print(a == b) // false
>>>
>>>     print(a != b) // true
>>>
>>> }
>>>
>>> Sample 3: A little investigation shows that `==` didn't call NSObject's `
>>> func isEqual(_ object: Any?) -> Bool` but `!=` did.
>>>
>>> class Foo:NSObject {
>>>
>>>     let name:String
>>>
>>>
>>>
>>>     init(name:String) {
>>>
>>>         self.name = name
>>>
>>>     }
>>>
>>>
>>>
>>>     public static func ==(lhs: Foo, rhs: Foo) -> Bool {
>>>
>>>         guard type(of:lhs) == type(of:rhs) else { return false }
>>>
>>>         return lhs.name == rhs.name
>>>
>>>     }
>>>
>>>
>>>
>>>     override func isEqual(to object: Any?) -> Bool {
>>>
>>>         print("111")
>>>
>>>         return super.isEqual(to: object)
>>>
>>>     }
>>>
>>>
>>>
>>>     override func isEqual(_ object: Any?) -> Bool {
>>>
>>>         print("2222")
>>>
>>>         return super.isEqual(object)
>>>
>>>     }
>>>
>>> }
>>>
>>>
>>> let a = Foo(name: "bar")
>>>
>>> let b = Foo(name: "bar")
>>>
>>>
>>> print(a == b) // true
>>>
>>> print(a != b) // 2222, true
>>>
>>> print(!(a == b)) // false
>>>
>>>
>>> So I am wondering what is the future? Will we keep on using `isEqual(_
>>>  object: Any?)` with class that inherits `NSObject`, or we are trying
>>> to drop it?
>>>
>>> Xcode  8.3.1 (8E1000a), 3.1 (swiftlang-802.0.51 clang-802.0.41), macOS 10.12.4
>>> (16E195)
>>>
>>> Zhaoxin
>>>
>>> _______________________________________________
>>> swift-users mailing list
>>> swift-users at swift.org
>>> https://lists.swift.org/mailman/listinfo/swift-users
>>>
>>>
>>
>>
>> --
>> Nate Birkholz
>>
>
>


-- 
Nate Birkholz
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20170418/4436804d/attachment.html>


More information about the swift-users mailing list