Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between using ObjectIdentifier() and '===' Operator

Let's say I'm implementing a root class in Swift, which I declare adopts the Equatable protocol (I want to be able to tell if an array of my type contains a given instance or not).

What is the difference -if any, in this specific case- between implementing the protocol's required == operator as:

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

    return ObjectIdentifier(lhs) == ObjectIdentifier(rhs)
}

...as opposed to just doing this:

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

    return (lhs === rhs)
}

As a reference, this is what the documentation says about ObjectIdentifier():

A unique identifier for a class instance or metatype. In Swift, only class instances and metatypes have unique identities. There is no notion of identity for structs, enums, functions, or tuples.

...and this is what the "Basic Operators" section of The Swift Programming Language (Swift 3) says about the === operator:

NOTE

Swift also provides two identity operators (=== and !==), which you use to test whether two object references both refer to the same object instance. For more information, see Classes and Structures.

like image 744
Nicolas Miari Avatar asked Sep 20 '16 06:09

Nicolas Miari


Video Answer


1 Answers

There is no difference for class instance, see the following comments in ObjectIdentifier.swift:

  /// Creates an instance that uniquely identifies the given class instance.
  ///
  /// The following example creates an example class `A` and compares instances
  /// of the class using their object identifiers and the identical-to
  /// operator (`===`):
  ///
  ///     class IntegerRef {
  ///         let value: Int
  ///         init(_ value: Int) {
  ///             self.value = value
  ///         }
  ///     }
  ///
  ///     let x = IntegerRef(10)
  ///     let y = x
  ///
  ///     print(ObjectIdentifier(x) == ObjectIdentifier(y))
  ///     // Prints "true"
  ///     print(x === y)
  ///     // Prints "true"
  ///
  ///     let z = IntegerRef(10)
  ///     print(ObjectIdentifier(x) == ObjectIdentifier(z))
  ///     // Prints "false"
  ///     print(x === z)
  ///     // Prints "false"
  ///

It also becomes apparent from the implementation of == for ObjectIdentifier, which just compares the pointers to the object storage:

  public static func == (x: ObjectIdentifier, y: ObjectIdentifier) -> Bool {
    return Bool(Builtin.cmp_eq_RawPointer(x._value, y._value))
  }

which is what the === operator does as well:

public func === (lhs: AnyObject?, rhs: AnyObject?) -> Bool {
  switch (lhs, rhs) {
  case let (l?, r?):
    return Bool(Builtin.cmp_eq_RawPointer(
        Builtin.bridgeToRawPointer(Builtin.castToUnknownObject(l)),
        Builtin.bridgeToRawPointer(Builtin.castToUnknownObject(r))
      ))
  case (nil, nil):
    return true
  default:
    return false
  }
}

ObjectIdentifier conforms to Hashable, so it is useful if you want to implement that protocol for your class:

extension MyClass: Hashable {
    var hashValue: Int {
        return ObjectIdentifier(self).hashValue
    }
}

An object identifier can also be created for meta types (e.g. ObjectIdentifier(Float.self)) for which === is not defined.

like image 111
Martin R Avatar answered Oct 20 '22 06:10

Martin R