Skip to content

Commit 1e861ac

Browse files
authored
Incorporate review comments
1 parent 31e9807 commit 1e861ac

File tree

1 file changed

+24
-30
lines changed

1 file changed

+24
-30
lines changed

stdlib/public/core/AnyHashable.swift

Lines changed: 24 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,11 @@ internal struct _ConcreteHashableBox<Base: Hashable>: _AnyHashableBox {
109109
/// The `AnyHashable` type forwards equality comparisons and hashing operations
110110
/// to an underlying hashable value, hiding the type of the wrapped value.
111111
///
112+
/// For types that support conversions between each other using `as` or `as?`
113+
/// (such as `Int` and `NSNumber`), `AnyHashable` treats their values as
114+
/// equivalent when type-erased by forwarding operations to canonical
115+
/// representations of the wrapped values.
116+
///
112117
/// You can store mixed-type keys in dictionaries and other collections that
113118
/// require `Hashable` conformance by wrapping mixed-type keys in
114119
/// `AnyHashable` instances:
@@ -124,16 +129,9 @@ internal struct _ConcreteHashableBox<Base: Hashable>: _AnyHashableBox {
124129
/// print(descriptions[AnyHashable(44)]) // prints "nil"
125130
/// print(descriptions[AnyHashable(Set(["a", "b"]))]!) // prints "a set of strings"
126131
///
127-
/// If the wrapped value is of a type that can be bridged using `as` to a
128-
/// different but compatible class defined in Foundation, or vice versa, then
129-
/// the underlying hashable value to which operations are forwarded might not be
130-
/// of the wrapped type itself but of a transitively bridged type:
131-
///
132-
/// let x: AnyHashable = [1, 2, 3] as NSArray
133-
/// let y: AnyHashable = [1, 2, 3] as [Double]
134-
/// let z: AnyHashable = [1, 2, 3] as [Int8]
135-
/// print(x == y, x.hashValue == y.hashValue) // prints "true true"
136-
/// print(y == z, y.hashValue == z.hashValue) // prints "true true"
132+
/// Note that `AnyHashable` instances are not guaranteed to preserve the hash
133+
/// encoding of their wrapped values, even in cases where hash values appear to
134+
/// match in a particular release of the standard library.
137135
@frozen
138136
public struct AnyHashable {
139137
internal var _box: _AnyHashableBox
@@ -165,7 +163,7 @@ public struct AnyHashable {
165163
/// The value wrapped by this instance.
166164
///
167165
/// The `base` property can be cast back to its original type using one of
168-
/// the casting operators (`as?`, `as!`, or `as`).
166+
/// the type casting operators (`as?`, `as!`, or `as`).
169167
///
170168
/// let anyMessage = AnyHashable("Hello world!")
171169
/// if let unwrappedMessage = anyMessage.base as? String {
@@ -200,21 +198,23 @@ public struct AnyHashable {
200198

201199
extension AnyHashable: Equatable {
202200
/// Returns a Boolean value indicating whether two type-erased hashable
203-
/// instances wrap the same value.
201+
/// instances wrap the same value of equivalent type.
204202
///
205-
/// Two instances of `AnyHashable` compare as equal if and only if the
206-
/// underlying types have the same conformance to the `Equatable` protocol
207-
/// and the underlying values compare as equal.
203+
/// `AnyHashable` considers bridged counterparts (such as a `String` and an
204+
/// `NSString`) of the same value to be equivalent when type-erased. Where
205+
/// those compatible types have different definitions of equality comparisons,
206+
/// values that originally compare as not equal may then compare as equal when
207+
/// they are type-erased by conversion to `AnyHashable`:
208208
///
209-
/// If the wrapped values are of a type that can be bridged using `as` to a
210-
/// different but compatible class defined in Foundation, or vice versa, then
211-
/// the underlying values compared might not be of the wrapped type itself but
212-
/// of a transitively bridged type:
213-
///
214-
/// let a = (42 as NSNumber as AnyHashable)
215-
/// let b = (42 as Double as AnyHashable)
216-
/// let c = (42 as Int8 as AnyHashable)
217-
/// print(a == b, b == c, a == c) // prints "true true true"
209+
/// let string1 = "café"
210+
/// let string2 = "cafe\u{301}" // U+301 COMBINING ACUTE ACCENT
211+
/// let nsString1 = string1 as NSString
212+
/// let nsString2 = string2 as NSString
213+
/// let typeErased1 = nsString1 as AnyHashable
214+
/// let typeErased2 = nsString2 as AnyHashable
215+
/// print(string1 == string2) // prints "true"
216+
/// print(nsString1 == nsString2) // prints "false"
217+
/// print(typeErased1 == typeErased2) // prints "true"
218218
///
219219
/// - Parameters:
220220
/// - lhs: A type-erased hashable value.
@@ -225,16 +225,10 @@ extension AnyHashable: Equatable {
225225
}
226226

227227
extension AnyHashable: Hashable {
228-
/// The hash value.
229228
public var hashValue: Int {
230229
return _box._canonicalBox._hashValue
231230
}
232231

233-
/// Hashes the essential components of this value by feeding them into the
234-
/// given hasher.
235-
///
236-
/// - Parameter hasher: The hasher to use when combining the components
237-
/// of this instance.
238232
public func hash(into hasher: inout Hasher) {
239233
_box._canonicalBox._hash(into: &hasher)
240234
}

0 commit comments

Comments
 (0)