[swift-users] Is it possible to store a set of heterogeneous items with protocol?
Howard Lovatt
howard.lovatt at gmail.com
Tue Jul 11 19:07:44 CDT 2017
I would be tempted to use classes for this if you can use single
inheritance. If you need multiple inheritance then use an enum and hand
code the dispatch, a lot more work :(. 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
}
}
enum AB1Or2: A, B, Hashable {
case ab1(AB1)
case ab2(AB2)
func a() -> String {
switch self {
case .ab1(let ab1Arg):
return ab1Arg.a()
case .ab2(let ab2Arg):
return ab2Arg.a()
}
}
func b() -> String {
switch self {
case .ab1(let ab1Arg):
return ab1Arg.b()
case .ab2(let ab2Arg):
return ab2Arg.b()
}
}
var hashValue: Int {
switch self {
case .ab1(let ab1Arg):
return ab1Arg.hashValue
case .ab2(let ab2Arg):
return ab2Arg.hashValue
}
}
static func ==(lhs: AB1Or2, rhs: AB1Or2) -> Bool {
switch lhs {
case .ab1(let lhsAB1):
switch rhs {
case .ab1(let rhsAB1):
return lhsAB1 == rhsAB1
default:
return false
}
case .ab2(let lhsAB2):
switch rhs {
case .ab2(let rhsAB2):
return lhsAB2 == rhsAB2
default:
return false
}
}
}
}
let ab1s = Set([AB1Or2.ab1(AB1())])
let ab2s = Set([AB1Or2.ab2(AB2())])
let abs = ab1s.union(ab2s)
On Tue, 11 Jul 2017 at 10:46 pm, Glen Huang <heyhgl at gmail.com> wrote:
> Thanks for bringing AnyHashable to my attention.
>
> It works, but the types are now erased. I want to have a union of the two
> sets because I want to loop over it to treat each contained item as Named,
> so I can process them as though they are of the same type. Is this type of
> use case really should be addressed using super class?
>
> On 11 Jul 2017, at 7:38 PM, Howard Lovatt <howard.lovatt at gmail.com> wrote:
>
> You can have a set of AnyHashable:
>
> var item = Set<AnyHashable>()
> item.insert(AnyHashable(Foo()))
> item.insert(AnyHashable(Bar()))
>
>
> Depends what you will do with the set if this is viable or not. You can
> also use classes and ObjectID.
>
> You might want this though:
>
> var item = [AnyHashable: Any]
>
> extension Dictionary where Key == AnyHashable, Value: Hashable {
> func insert(_ value: Value) {
> self[AnyHashable(value)] == value
> }
> }
>
> item.insert(Foo())
> item.insert(Bar())
>
>
> So you get at the stored value.
>
> -- Howard.
>
> On 11 Jul 2017, at 8:09 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/20170712/aa9ca812/attachment.html>
More information about the swift-users
mailing list