[swift-users] odd `==` `!=` behavior with class that inherits `NSObject`
Zhao Xin
owenzx at gmail.com
Wed Apr 19 03:59:32 CDT 2017
Hi Nate,
It my personal habit to use do-block to compare different Objects with the
same name. For example,
do {
class A {
// some staff
}
let a = A()
// some other staff
}
do {
class A {
func foo() {}
// some staff
}
let a = A()
// some other staff
}
I don't need to comment/uncomment with do-block when testing my code.
I think for NSObject's `isEqual(_)`, there is a big change and the change
is never mentioned in any docs. As far as I know, `==` had never worked
with NSObject instances in the past. Because only `isEqual(_)` is used.
`==` wouldn't be called at all.
In today's examples, `==` override the behavior `isEqual(_)`. The change is
huge. Because if `==` is never called, someone like me will notice and then
change his own code to override `isEqual(_)`. Now `isEqual(_)` is some how
abandoned if `==` and `!=` is implemented. That never happens before.
// prior Swift, NSObject instances
find code `a==b`, call `a.isEqual(b)`
// now Swift,
find code `a==b`, call ` if has operator `==``, call `a==b`; else call
`a.isEqual(b)`
Zhaoxin
On Wed, Apr 19, 2017 at 11:31 AM, Nate Birkholz <nbirkholz at gmail.com> wrote:
> 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/20170419/c53f3136/attachment.html>
More information about the swift-users
mailing list