@@ -109,6 +109,11 @@ internal struct _ConcreteHashableBox<Base: Hashable>: _AnyHashableBox {
109
109
/// The `AnyHashable` type forwards equality comparisons and hashing operations
110
110
/// to an underlying hashable value, hiding the type of the wrapped value.
111
111
///
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
+ ///
112
117
/// You can store mixed-type keys in dictionaries and other collections that
113
118
/// require `Hashable` conformance by wrapping mixed-type keys in
114
119
/// `AnyHashable` instances:
@@ -124,16 +129,9 @@ internal struct _ConcreteHashableBox<Base: Hashable>: _AnyHashableBox {
124
129
/// print(descriptions[AnyHashable(44)]) // prints "nil"
125
130
/// print(descriptions[AnyHashable(Set(["a", "b"]))]!) // prints "a set of strings"
126
131
///
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.
137
135
@frozen
138
136
public struct AnyHashable {
139
137
internal var _box : _AnyHashableBox
@@ -165,7 +163,7 @@ public struct AnyHashable {
165
163
/// The value wrapped by this instance.
166
164
///
167
165
/// 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`).
169
167
///
170
168
/// let anyMessage = AnyHashable("Hello world!")
171
169
/// if let unwrappedMessage = anyMessage.base as? String {
@@ -200,21 +198,23 @@ public struct AnyHashable {
200
198
201
199
extension AnyHashable : Equatable {
202
200
/// 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 .
204
202
///
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`:
208
208
///
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"
218
218
///
219
219
/// - Parameters:
220
220
/// - lhs: A type-erased hashable value.
@@ -225,16 +225,10 @@ extension AnyHashable: Equatable {
225
225
}
226
226
227
227
extension AnyHashable : Hashable {
228
- /// The hash value.
229
228
public var hashValue : Int {
230
229
return _box. _canonicalBox. _hashValue
231
230
}
232
231
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.
238
232
public func hash( into hasher: inout Hasher ) {
239
233
_box. _canonicalBox. _hash ( into: & hasher)
240
234
}
0 commit comments