Add AnyHashable to the standard library


(Dmitri Gribenko) #1

Hi,

The implementation of SE-0116 "Import Objective-C id as Swift Any type"
requires a type-erased container for hashable values.

We are proposing to add such a type-erased container under the name
AnyHashable to the standard library.

This proposal is additive, source-breaking changes are discussed in SE-0116.

/// A type-erased hashable value.////// Forwards equality comparisons
and hashing operations to an/// underlying hashable value, hiding its
specific type.////// You can store mixed-type keys in `Dictionary` and
other/// collections that require `Hashable` by wrapping mixed-type
keys in/// `AnyHashable` instances:////// let descriptions:
[AnyHashable : Any] = [/// AnyHashable(":smile:"): "emoji",///
   AnyHashable(42): "an Int",/// AnyHashable(Int8(43)): "an
Int8",/// AnyHashable(Set(["a", "b"])): "a set of strings"///
   ]/// print(descriptions[AnyHashable(42)]!) // prints "an
Int"/// print(descriptions[AnyHashable(43)]) // prints
"nil"/// print(descriptions[AnyHashable(Int8(43))]!) // prints "an
Int8"/// print(descriptions[AnyHashable(Set(["a", "b"]))]!) //
prints "a set of strings"public struct AnyHashable {
  /// Creates an opaque hashable value that wraps `base`.
  ///
  /// Example:
  ///
  /// let x = AnyHashable(Int(42))
  /// let y = AnyHashable(UInt8(42))
  ///
  /// print(x == y) // Prints "false" because `Int` and `UInt8`
  /// // are different types.
  ///
  /// print(x == AnyHashable(Int(42))) // Prints "true".
  public init<H : Hashable>(_ base: H)

  /// The value wrapped in this `AnyHashable` instance.
  ///
  /// let anyMessage = AnyHashable("Hello")
  /// let unwrappedMessage: Any = anyMessage.base
  /// print(unwrappedMessage) // prints "hello"
  public var base: Any
}
extension AnyHashable : Equatable, Hashable {
  public static func == (lhs: AnyHashable, rhs: AnyHashable) -> Bool
  public var hashValue: Int {
}

We are adding convenience APIs to Set<AnyHashable> that allow using
existing Set APIs with concrete values that conform to Hashable. For
example:

func contains42(_ data: Set<AnyHashable>) -> Bool {
  // Works, but is too verbose:
  // return data.contains(AnyHashable(42))

  return data.contains(42) // Convenience API.
}

extension Set where Element == AnyHashable {
  public func contains<ConcreteElement : Hashable>(
    _ member: ConcreteElement
  ) -> Bool

  public func index<ConcreteElement : Hashable>(
    of member: ConcreteElement
  ) -> SetIndex<Element>?

  mutating func insert<ConcreteElement : Hashable>(
    _ newMember: ConcreteElement
  ) -> (inserted: Bool, memberAfterInsert: ConcreteElement)

  @discardableResult
  mutating func update<ConcreteElement : Hashable>(
    with newMember: ConcreteElement
  ) -> ConcreteElement?

  @discardableResult
  mutating func remove<ConcreteElement : Hashable>(
    _ member: ConcreteElement
  ) -> ConcreteElement?
}

Convenience APIs for Dictionary<AnyHashable, *>:

extension Dictionary where Key == AnyHashable {
  public func index<ConcreteKey : Hashable>(forKey key: ConcreteKey)
    -> DictionaryIndex<Key, Value>?

  public subscript(_ key: _Hashable) -> Value? { get set }

  @discardableResult
  public mutating func updateValue<ConcreteKey : Hashable>(
    _ value: Value, forKey key: ConcreteKey
  ) -> Value?

  @discardableResult
  public mutating func removeValue<ConcreteKey : Hashable>(
    forKey key: ConcreteKey
  ) -> Value?
}

Dmitri

···

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com>*/


(Dmitri Gribenko) #2

You can view the full proposal here:
https://github.com/apple/swift-evolution/pull/458/files

Dmitri

···

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com>*/


(Erica Sadun) #3

The proposal looks solid. I would be in favor.

-- E

···

On Jul 22, 2016, at 4:34 PM, Dmitri Gribenko via swift-evolution <swift-evolution@swift.org> wrote:

You can view the full proposal here:
https://github.com/apple/swift-evolution/pull/458/files

Dmitri


(Paul Cantrell) #4

The proposal mostly just makes me long for robust existentials. Sigh.

But yes, given the limitations of Swift 3, this does seem useful.

P

···

On Jul 22, 2016, at 6:15 PM, Erica Sadun via swift-evolution <swift-evolution@swift.org> wrote:

On Jul 22, 2016, at 4:34 PM, Dmitri Gribenko via swift-evolution <swift-evolution@swift.org> wrote:

You can view the full proposal here:
https://github.com/apple/swift-evolution/pull/458/files

Dmitri

The proposal looks solid. I would be in favor.