[swift-dev] Pure Cocoa NSNumbers and AnyHashable

Joe Groff jgroff at apple.com
Wed Nov 2 12:26:24 CDT 2016

There's a hole in our AnyHashable implementation when it comes to what I'll call "pure" NSNumbers coming from Cocoa, which were instantiated using -[NSNumber numberWith*:] factories or @(n) syntax in Objective-C. While we maintain type specificity when Swift number types are bridged through NSNumber, NSNumbers constructed in ObjC do not necessarily remember the type they were constructed with or expect to be strictly used as only that type, so we resign to being "fuzzy" and let them bridge back to any Swift type. We however fail to bring this fuzziness to AnyHashable. When we construct an AnyHashable, we'll bring bridged NSNumbers back to their original Swift types, but we leave a pure NSNumber as an NSNumber, so it doesn't hash or equate with numeric values in Swift:

// ObjC
@import Foundation;

NSDictionary *foo() {
  return @{@(1): @"one"};

// Swift
let theFoo /*: [AnyHashable: Any]*/ = foo()
theFoo[1] // returns nil, ought to find the value "one"

One way to address this would be to make Swift's number types use the same hashing as NSNumber does. We could go so far as to switch the "custom AnyHashable" polarity around and coerce the Swift number types into NSNumbers when we put them inside AnyHashable, which would give us consistent hashing and fuzzy equality, but would come at a performance cost when converting a number to AnyHashable. We would also lose type specificity in equality for Swift values, since NSNumber's -isEqual: only compares numeric value, unless we special-cased NSNumber in AnyHashable's implementation.

If we didn't want to adopt NSNumber's hashing for Swift's types, but we were willing to say that all of Swift's number types produce the same hashValue for the same numeric value (so 12.hashValue == 12.0.hashValue == (12 as UInt8).hashValue, etc.), we could also go the other direction, and customize a pure NSNumber's AnyHashable implementation to use Swift's number hashing. We would still need special handling for equality of a pure NSNumber with Swift numbers, but maybe that's inevitable.

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-dev/attachments/20161102/8fe04828/attachment.html>

More information about the swift-dev mailing list