Skip to content

Commit bbd888f

Browse files
authored
Merge pull request #29498 from xwu/any-hashable-docs
[docs] Update AnyHashable documentation
2 parents b628710 + 06f12fc commit bbd888f

File tree

1 file changed

+37
-20
lines changed

1 file changed

+37
-20
lines changed

stdlib/public/core/AnyHashable.swift

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -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
127138
public 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

190201
extension 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

206229
extension 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

Comments
 (0)