Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type any <Protocol> cannot conform to Hashable

I'm playing with the Swift 5.7 new capabilities and I'm trying to implement some heterogeneous Sets.

I've reduced my code to this simple playground:

protocol Stuff: Hashable {
    var identifier: String { get }
}

struct StuffA: Stuff {
    let identifier: String
    
    func hash(into hasher: inout Hasher) {
        hasher.combine(identifier)
    }
}

struct StuffB: Stuff {
    let identifier: String
    
    func hash(into hasher: inout Hasher) {
        hasher.combine(identifier)
    }
}

var arrayOfStuff: Array<any Stuff> = []
arrayOfStuff.append(StuffA(identifier: "a"))
arrayOfStuff.append(StuffB(identifier: "b"))
// Works like a charm

var setOfStuff: Set<any Stuff> = Set() 
// error: Type 'any Stuff' cannot conform to 'Hashable'
setOfStuff.insert(StuffA(identifier: "a"))
setOfStuff.insert(StuffB(identifier: "b"))

The first try with Array<any Stuff> shows any can be used with a protocol to specify a generic constraint.

The second try fails because swift cannot checks the Hashable conformance. I know that Stuff does not conforms to Hashable, it only inherits from. But how do you tell the compiler that any Stuff will conform?

like image 530
Martin Avatar asked Jan 19 '26 02:01

Martin


1 Answers

The issue is that Set requires a concrete type not an "any". This is a frustrating part of swift for now. You would have to make a type that conforms to the protocol, but still explicitly make it conform to a separate requirement/protocol?. I've recently run into the same situation in complex code and it's a real bummer. Basically you would have to make an arbitrary type that conforms to your protocol and the required "Hashable" In my case I made a LineItem wrapper that wraps a "any LineItemRepresentable(my protocol)" and conforms to the requirement that I couldn't just support by requiring the protocol to support it..

here's an example

protocol SomeProtocol {
    var item {get set}
}
    
class MyClass: Hashable {
    var wrappedValue: any SomeProtocol
    
    // init...
    
    var item: Item {
       get {
          wrappedValue.item
       }
       set {
          wrappedValue.item = newValue
       }
    }
 }
like image 107
user20325868 Avatar answered Jan 21 '26 20:01

user20325868



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!