[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