Reputation: 10136
The documentation for Set
's insert
method states:
Return Value
(true, newMember)
ifnewMember
was not contained in the set. If an element equal tonewMember
was already contained in the set, the method returns(false, oldMember)
, whereoldMember
is the element that was equal tonewMember
.In some cases,
oldMember
may be distinguishable fromnewMember
by identity comparison or some other means.
What are the cases when oldMember
might be distinguishable from newMember
they are talking about? Any example?
Reason for the question: I have a Set
that contains objects that are not necessarily Hashable
. I had the idea to use Unmanaged.passUnretained(object).toOpaque().hashValue
to get a hash-value for just any object (basically from its address) in a wrapper struct, however the above bit in the documentation makes me wary.
Upvotes: 1
Views: 131
Reputation: 80901
If you have some way to tell two instances apart even when they compare equal by their implementation of Equatable
's ==
operator, then you can use this to compare the element to insert with the memberAfterInsert
returned by insert(_:)
.
A prime example of this, as the documentation says, is the identity comparison (===
). Two object instances that compare equal may not necessarily be the exact same instance (i.e have the same address).
For example:
class Foo : Hashable {
static func ==(lhs: Foo, rhs: Foo) -> Bool {
return lhs.foo == rhs.foo
}
var hashValue: Int {
return foo
}
let foo: Int
init(_ foo: Int) {
self.foo = foo
}
}
var set : Set = [Foo(10)]
let toInsert = Foo(10)
let result = set.insert(toInsert) // the element toInsert will compare equal to the element
// already in the set, thus the element already in the
// already in the set will be returned.
print(result) // (false, Foo) – false, as element was already in set
print(result.memberAfterInsert == toInsert) // true – obviously they were equal.
print(result.memberAfterInsert === toInsert) // false – but they weren't the same instance.
In your case of using a hash value based on the identity, as long as your Equatable
implementation also relies on the identity, you won't break the contract of Hashable
(instances that compare equal with ==
must have the same hashValue
) – although obviously you won't be able to use the identity to differentiate the memberAfterInsert
with the element you are trying to insert.
However it's worth noting that having a Set
where the Element
's equality implementation is solely based on identity may cause surprising results for objects that look like they should be equivalent. For example, it would be perfectly fine to have a set of [Foo(5), Foo(5), Foo(5), Foo(5)]
, given that the objects are different instances.
Upvotes: 1