@@ -107,22 +107,33 @@ internal struct _ConcreteHashableBox<Base: Hashable>: _AnyHashableBox {
107107/// A type-erased hashable value.
108108///
109109/// The `AnyHashable` type forwards equality comparisons and hashing operations
110- /// to an underlying hashable value, hiding its specific underlying type.
110+ /// to an underlying hashable value, hiding the type of the wrapped value.
111+ ///
112+ /// Where conversion using `as` or `as?` is possible between two types (such as
113+ /// `Int` and `NSNumber`), `AnyHashable` uses a canonical representation of the
114+ /// type-erased value so that instances wrapping the same value of either type
115+ /// compare as equal. For example, `AnyHashable(42)` compares as equal to
116+ /// `AnyHashable(42 as NSNumber)`.
111117///
112118/// You can store mixed-type keys in dictionaries and other collections that
113119/// require `Hashable` conformance by wrapping mixed-type keys in
114120/// `AnyHashable` instances:
115121///
116122/// let descriptions: [AnyHashable: Any] = [
117- /// AnyHashable("😄"): "emoji",
118- /// AnyHashable(42): "an Int",
119- /// AnyHashable(Int8(43)): "an Int8",
120- /// AnyHashable(Set(["a", "b"])): "a set of strings"
123+ /// 42: "an Int",
124+ /// 43 as Int8: "an Int8",
125+ /// ["a", "b"] as Set: "a set of strings"
121126/// ]
122- /// print(descriptions[AnyHashable(42)]!) // prints "an Int"
123- /// print(descriptions[AnyHashable(45)]) // prints "nil"
124- /// print(descriptions[AnyHashable(Int8(43))]!) // prints "an Int8"
125- /// print(descriptions[AnyHashable(Set(["a", "b"]))]!) // prints "a set of strings"
127+ /// print(descriptions[42]!) // prints "an Int"
128+ /// print(descriptions[42 as Int8]!) // prints "an Int"
129+ /// print(descriptions[43 as Int8]!) // prints "an Int8"
130+ /// print(descriptions[44]) // prints "nil"
131+ /// print(descriptions[["a", "b"] as Set]!) // prints "a set of strings"
132+ ///
133+ /// Note that `AnyHashable` does not guarantee that it preserves the hash
134+ /// encoding of wrapped values. Do not rely on `AnyHashable` generating such
135+ /// compatible hashes, as the hash encoding that it uses may change between any
136+ /// two releases of the standard library.
126137@frozen
127138public struct AnyHashable {
128139 internal var _box : _AnyHashableBox
@@ -154,7 +165,7 @@ public struct AnyHashable {
154165 /// The value wrapped by this instance.
155166 ///
156167 /// The `base` property can be cast back to its original type using one of
157- /// the casting operators (`as?`, `as!`, or `as`).
168+ /// the type casting operators (`as?`, `as!`, or `as`).
158169 ///
159170 /// let anyMessage = AnyHashable("Hello world!")
160171 /// if let unwrappedMessage = anyMessage.base as? String {
@@ -189,11 +200,23 @@ public struct AnyHashable {
189200
190201extension AnyHashable : Equatable {
191202 /// Returns a Boolean value indicating whether two type-erased hashable
192- /// instances wrap the same type and value.
203+ /// instances wrap the same value.
193204 ///
194- /// Two instances of `AnyHashable` compare as equal if and only if the
195- /// underlying types have the same conformance to the `Equatable` protocol
196- /// and the underlying values compare as equal.
205+ /// `AnyHashable` considers bridged counterparts (such as a `String` and an
206+ /// `NSString`) of the same value to be equivalent when type-erased. If those
207+ /// compatible types use different definitions for equality, values that were
208+ /// originally distinct might compare as equal when they are converted to
209+ /// `AnyHashable`:
210+ ///
211+ /// let string1 = "café"
212+ /// let string2 = "cafe\u{301}" // U+301 COMBINING ACUTE ACCENT
213+ /// let nsString1 = string1 as NSString
214+ /// let nsString2 = string2 as NSString
215+ /// let typeErased1 = nsString1 as AnyHashable
216+ /// let typeErased2 = nsString2 as AnyHashable
217+ /// print(string1 == string2) // prints "true"
218+ /// print(nsString1 == nsString2) // prints "false"
219+ /// print(typeErased1 == typeErased2) // prints "true"
197220 ///
198221 /// - Parameters:
199222 /// - lhs: A type-erased hashable value.
@@ -204,16 +227,10 @@ extension AnyHashable: Equatable {
204227}
205228
206229extension AnyHashable : Hashable {
207- /// The hash value.
208230 public var hashValue : Int {
209231 return _box. _canonicalBox. _hashValue
210232 }
211233
212- /// Hashes the essential components of this value by feeding them into the
213- /// given hasher.
214- ///
215- /// - Parameter hasher: The hasher to use when combining the components
216- /// of this instance.
217234 public func hash( into hasher: inout Hasher ) {
218235 _box. _canonicalBox. _hash ( into: & hasher)
219236 }
0 commit comments