[swift-users] ⁨Is it possible to store a set of heterogeneous items with protocol?

Howard Lovatt howard.lovatt at gmail.com
Wed Jul 19 18:53:54 CDT 2017


You are hardly alone struggling with this, it seems to come up every other
week!

You can write your own custom AnyProtocol type that includes Self, a pain
but doable, e.g.:

protocol A {
    func a() -> String
}
protocol B {
    func b() -> String
}
struct AB1: A, B, Hashable {
    func a() -> String {
        return "AB1.a"
    }
    func b() -> String {
        return "AB1.b"
    }
    var hashValue: Int {
        return 1
    }
    static func ==(lhs: AB1, rhs: AB1) -> Bool {
        return true
    }
}
struct AB2: A, B, Hashable {
    func a() -> String {
        return "AB2.a"
    }
    func b() -> String {
        return "AB2.b"
    }
    var hashValue: Int {
        return 2
    }
    static func ==(lhs: AB2, rhs: AB2) -> Bool {
        return true
    }
}
struct AnyABHashable: A, B, Hashable {
    let equalsClosure: (_ rhs: AnyABHashable) -> Bool
    let hashValueClosure: () -> Int
    let bClosure: () -> String
    let aClosure: () -> String
    static func ==(lhs: AnyABHashable, rhs: AnyABHashable) -> Bool {
        return lhs.equalsClosure(rhs)
    }
    var hashValue: Int {
        return hashValueClosure()
    }
    func b() -> String {
        return bClosure()
    }
    func a() -> String {
        return aClosure()
    }
}
// AB1 init
extension AnyABHashable {
    init(_ ab1: AB1) {
        equalsClosure = { (r) in
            if let rhs = r as? AB1 {
                return ab1 == rhs
            }
            return false
        }
        hashValueClosure = { return ab1.hashValue }
        aClosure = { return ab1.a() }
        bClosure = { return ab1.b() }
    }
}
// AB2 init
extension AnyABHashable {
    init(_ ab2: AB2) {
        equalsClosure = { (r) in
            if let rhs = r as? AB2 {
                return ab2 == rhs
            }
            return false
        }
        hashValueClosure = { return ab2.hashValue }
        aClosure = { return ab2.a() }
        bClosure = { return ab2.b() }
    }
}
let ab1Set = Set([AnyABHashable(AB1())])
let ab2Set = Set([AnyABHashable(AB2())])
let abSet = ab1Set.union(ab2Set)
for ab in abSet {
    ab.a()
    ab.b()
}


On Tue, 11 Jul 2017 at 8:10 pm, Glen Huang via swift-users <
swift-users at swift.org> wrote:

> Hi,
>
> I want to store some heterogeneous items all conform to a protocol inside
> a set, is it something possible to do in swift?
>
> I tried this example:
>
> ```
> protocol Named: Hashable {
>    var name: String { get }
> }
>
> extension Named {
>    var hashValue: Int {
>        return name.hashValue
>    }
>
>    static func ==(lhs: Self, rhs: Self) -> Bool {
>        return lhs.name == rhs.name
>    }
> }
>
> struct Foo: Named {
>    var name = "foo"
> }
>
> struct Bar: Named {
>    var name = "bar"
> }
>
> var item = Set<Named>()
> item.insert(Foo())
> item.insert(Bar())
> ```
>
> But it failed at `Set<Named>()` where it complained "Using 'Named' as a
> concrete type conforming to protocol 'Hashable' is not supported”.
>
> After watching the WWDC session "Protocol-Oriented Programming in Swift”
> by Dave Abrahams, I try to use protocols whenever possible. But I can’t
> seem to overcome this barrier. Set.Element must confirm to Hashable, which
> inherits from Equatable, which has self requirement, which ultimately means
> that Set.Element all must be of the same type. So it seems it’s impossible
> to have heterogeneous items using protocol. Is that the case?
>
> My use case is this:
>
> I have an object that can contain two sets of other objects:
>
> ```
> class Parent {
>    var foos: Set<Foo>
>    var bars: Set<Bar>
> }
> ```
>
> I want to define a computed property “all” that is the union of the two
> sets. Foo and Bar conform to the same protocol. I wonder what return type I
> should use for the union? Do I have to go back to OOP and define a super
> class for Foo and Bar?
>
> Thanks.
> _______________________________________________
> swift-users mailing list
> swift-users at swift.org
> https://lists.swift.org/mailman/listinfo/swift-users
>
-- 
-- Howard.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20170719/7373b4f8/attachment.html>


More information about the swift-users mailing list