ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [SE-0514] Hashable Conformance for Dictionary.Keys, CollectionOfOne and EmptyCollection
    Swift 2026. 3. 2. 09:14

    안녕하세요. 그린입니다 🍏

    이번 포스팅에서는 SE-0514 Hashable Conformance for Dictionary.Keys, CollectionOfOne and EmptyCollection에 대해 정리해보겠습니다 🙋🏻


    Intro

    Swift 표준 라이브러리의 몇몇 collection 타입들이 Hashable을 conform하지 않는 게 있습니다.

    Dictionary.Keys, CollectionOfOne, EmptyCollection이 바로 그것들인데요.

     

    이번 SE-0514는 이 세 타입에 Hashable conformance를 추가하는 제안입니다.

     

    특히 Dictionary.Keys는 모든 key가 이미 Hashable인데 keys view 자체는 Hashable이 아닌 게 좀 이상하죠.

    간단하지만 일관성을 높여주는 개선입니다 🚀

     

    현재 2026년 3월 6일까지 리뷰가 진행 중입니다!

     


    왜 필요한가?

    Dictionary.Keys

    Dictionary.Keys는 단순히 dictionary의 keys에 대한 view입니다.

    Dictionary의 모든 key는 Hashable을 conform하죠.

    따라서 Dictionary.Keys 자체도 자동으로 그리고 무조건적으로 Hashable을 conform해야 합니다.

     

    CollectionOfOne과 EmptyCollection

    CollectionOfOne과 EmptyCollection은 상대적으로 덜 사용되는 타입들입니다.

    이들에 Hashable conformance를 추가하는 건 완전성과 다른 표준 라이브러리 collection 타입들과의 일관성을 위해서입니다.

     

    참고로 CollectionOfOne은 Equatable도 conform하지 않아서, 이 제안에서는 그것도 함께 추가합니다.

     


    솔루션

    표준 라이브러리에 다음을 추가합니다.

    • Dictionary.Keys와 EmptyCollection: 무조건적 Hashable conformance
    • CollectionOfOne: 조건부 Equatable과 Hashable conformance

    상세 설계

    Dictionary.Keys

    Dictionary.Keys는 무조건적인 Hashable conformance를 얻습니다.

    Dictionary의 key는 항상 Hashable이니까요.

     

    Hash 구현은 commutative hashing algorithm(개별 element hash의 XOR)을 사용해서, 두 Dictionary.Keys collection이 같은 element를 포함하면 iteration order와 관계없이 같은 hash value를 갖도록 합니다.

    extension Dictionary.Keys {
      @_alwaysEmitIntoClient
      public func hash(into hasher: inout Hasher) {
        var commutativeHash = 0
        for element in self {
          // Note that, similar to `Set`'s and `Dictionary`'s hashing algorithms, we use a copy of our own hasher here.
          // This makes hash values dependent on its state, eliminating static collision patterns.
          var elementHasher = hasher
          elementHasher.combine(element)
          commutativeHash ^= elementHasher._finalize()
        }
        hasher.combine(commutativeHash)
      }
    
      @_alwaysEmitIntoClient
      public var hashValue: Int { // Prevent compiler from synthesizing hashValue.
        var hasher = Hasher()
        self.hash(into: &hasher)
        return hasher.finalize()
      }
    }
    
    @available(SwiftStdlib 6.4, *)
    extension Dictionary.Keys: Hashable {}

     

    사용 예시

    let batch1 = ["apple": 1, "banana": 2, "cherry": 3, "date": 4]
    let batch2 = ["date": 10, "banana": 20, "apple": 30, "cherry": 40]
    let batch3 = ["mango": 5, "orange": 6, "papaya": 7]
    
    let uniqueBatches = Set([batch1.keys, batch2.keys, batch3.keys])
    
    print(uniqueBatches)
    // [Dictionary.Keys(["orange", "mango", "papaya"]), Dictionary.Keys(["banana", "apple", "date", "cherry"])]

     

     

    batch1.keys와 batch2.keys는 같은 key들을 포함하므로 Set에서 하나로 처리됩니다!

     

     


    CollectionOfOne

    CollectionOfOne은 조건부 conformance를 얻습니다.

    • Element가 Equatable이면 Equatable
    • Element가 Hashable이면 Hashable

     

    Hash value는 포함하고 있는 단일 element에서 파생됩니다.

    extension CollectionOfOne where Element: Equatable {
      @_alwaysEmitIntoClient
      public static func ==(lhs: CollectionOfOne<Element>, rhs: CollectionOfOne<Element>) -> Bool {
        return lhs._element == rhs._element
      }
    }
    
    extension CollectionOfOne where Element: Hashable {
      @_alwaysEmitIntoClient
      public func hash(into hasher: inout Hasher) {
        hasher.combine(self._element)
      }
    
      @_alwaysEmitIntoClient
      public var hashValue: Int { // Prevent compiler from synthesizing hashValue.
        var hasher = Hasher()
        self.hash(into: &hasher)
        return hasher.finalize()
      }
    }
    
    @available(SwiftStdlib 6.4, *)
    extension CollectionOfOne: Equatable where Element: Equatable {}
    
    @available(SwiftStdlib 6.4, *)
    extension CollectionOfOne: Hashable where Element: Hashable {}

     

     


    EmptyCollection

    EmptyCollection은 무조건적인 Hashable conformance를 얻습니다.

     

    모든 empty collection은 element 타입과 관계없이 동일하므로, 모두 같은 hash value를 가집니다.

    Hash 함수는 단순히 값 0을 combine하는데, 이는 empty set, dictionary, array의 hashing convention과 일치합니다.

    extension EmptyCollection {
      @_alwaysEmitIntoClient
      public func hash(into hasher: inout Hasher) {
        hasher.combine(0)
      }
    
      @_alwaysEmitIntoClient
      public var hashValue: Int { // Prevent compiler from synthesizing hashValue.
        var hasher = Hasher()
        self.hash(into: &hasher)
        return hasher.finalize()
      }
    }
    
    @available(SwiftStdlib 6.4, *)
    extension EmptyCollection: Hashable {}

     

     


    호환성

    Source compatibility

    순수하게 additive한 변경입니다.

    다만 이미 자체적으로 redundant conformance를 제공한 코드는 경고가 발생할 수 있습니다.

     

    ABI compatibility

    표준 라이브러리 ABI의 순수한 확장이고, 기존 기능은 변경하지 않습니다.

     


    Adoption 영향

    새로운 conformance는 Swift 6.4 이상이 필요합니다.

     

    이전 Swift 버전을 지원해야 한다면 이렇게 하면 됩니다.

    #if swift(<6.4)
      extension Dictionary.Keys: @retroactive Hashable {}
    #endif

     

     

    FYI. 이전 Swift 버전에서 이미 이런 함수를 구현했다면, 런타임에 binary compatibility 이슈가 발생할 낮은 이론적 위험이 있습니다.

    특히 구현이 표준 라이브러리 구현과 근본적으로 호환되지 않거나 충돌하는 경우입니다.

     

     


    고려된 대안

    EmptyCollection의 Hashable conformance를 포함하지 않기?

    완전성과 다른 표준 라이브러리 collection 타입들과의 일관성 외에도, hash-based context에서 EmptyCollection을 사용하는 케이스는 피할 수 있습니다.

    예를 들어 result ?? EmptyCollection<T> 대신 다른 방법을 쓸 수도 있죠.

    하지만 그런 workaround가 해당 use case에 idiomatic하지 않을 수 있습니다.

     

    그래서 일관성을 위해 포함시키기로 했습니다.

     

     


    Conclusion

    현재 SE-0514는 2026년 3월 6일까지 리뷰가 진행 중입니다.

    개인적으로는 정말 당연하게 있어야 할 conformance들이라고 생각합니다.

    특히 Dictionary.Keys는 모든 key가 이미 Hashable인데 keys view가 Hashable이 아닌 게 이상했거든요.

    CollectionOfOne과 EmptyCollection은 덜 사용되지만, 표준 라이브러리의 일관성을 높여주는 좋은 제안이라 생각됩니다 😃

     


    References

     

    swift-evolution/proposals/0514-hashable-conformance-for-dictionarykeys-collectionofone-emptycollection.md at main · swiftlang/s

    This maintains proposals for changes and user-visible enhancements to the Swift Programming Language. - swiftlang/swift-evolution

    github.com

     

    [Pitch] Hashable Conformance for Dictionary.Keys, CollectionOfOne and EmptyCollection

    Introduction This proposal adds Hashable conformance to three standard library collection types: Dictionary.Keys, CollectionOfOne and EmptyCollection. Motivation Dictionary.Keys Dictionary.Keys is simply a view of the dictionary's keys, and every key in a

    forums.swift.org

     

    SE-0514: Hashable Conformance for Dictionary.Keys, CollectionOfOne and EmptyCollection

    Hello, Swift community! The review of SE-0514: Hashable Conformance for Dictionary.Keys, CollectionOfOne and EmptyCollection begins now and runs through March 6, 2026. Reviews are an important part of the Swift evolution process. All review feedback should

    forums.swift.org

Designed by Tistory.