<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><div class="">Thanks for the code sample and link, but if I’m not wrong, this pattern doesn’t allow heterogeneous items.</div><div class=""><br class=""></div><div class="">If I have these definitions:</div><div class=""><br class=""></div>struct Chicken {}<br class="">struct Pig {}<br class=""><br class="">class ChickenFarm: Farm {<br class=""> func grow() -> Chicken {<br class=""> return Chicken()<br class=""> }<br class="">}<br class=""><br class="">class PigFarm: Farm {<br class=""> func grow() -> Pig {<br class=""> return Pig()<br class=""> }<br class="">}<br class=""><div class=""><div class=""><br class=""></div><div class="">Then:</div><div class=""><br class=""></div><div class="">var farms = // How do I define a set that can contain both ChickenFarm and PigFarm?<br class="">farms.insert(AnyFarm<Chicken>(ChickenFarm()))<br class="">farms.insert(AnyFarm<Pig>(PigFarm()))</div><div class=""><br class=""><div><br class=""><blockquote type="cite" class=""><div class="">On 17 Jul 2017, at 4:02 AM, Nevin Brackett-Rozinsky <<a href="mailto:nevin.brackettrozinsky@gmail.com" class="">nevin.brackettrozinsky@gmail.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class="">The standard pattern for type-erasure in Swift looks like this:<div class=""><br class=""></div><div class=""><div class=""><font face="monospace, monospace" class="">protocol Farm {</font></div><div class=""><font face="monospace, monospace" class=""> associatedtype Produce</font></div><div class=""><font face="monospace, monospace" class=""> func grow() -> Produce</font></div><div class=""><font face="monospace, monospace" class="">}</font></div><div class=""><font face="monospace, monospace" class=""><br class=""></font></div><div class=""><font face="monospace, monospace" class="">private class _AnyFarmBase<T> : Farm {</font></div><div class=""><font face="monospace, monospace" class=""> func grow() -> T { fatalError() }</font></div><div class=""><font face="monospace, monospace" class="">}</font></div><div class=""><font face="monospace, monospace" class=""><br class=""></font></div><div class=""><font face="monospace, monospace" class="">private final class _AnyFarmBox<U: Farm>: _AnyFarmBase<U.Produce> {</font></div><div class=""><font face="monospace, monospace" class=""> var farm: U</font></div><div class=""><font face="monospace, monospace" class=""> init(_ x: U) { farm = x }</font></div><div class=""><font face="monospace, monospace" class=""> override func grow() -> U.Produce {</font></div><div class=""><font face="monospace, monospace" class=""> return farm.grow()</font></div><div class=""><font face="monospace, monospace" class=""> }</font></div><div class=""><font face="monospace, monospace" class="">}</font></div><div class=""><font face="monospace, monospace" class=""><br class=""></font></div><div class=""><font face="monospace, monospace" class="">public final class AnyFarm<V> : Farm {</font></div><div class=""><font face="monospace, monospace" class=""> private let wrapped: _AnyFarmBase<V></font></div><div class=""><font face="monospace, monospace" class=""> func grow() -> V { return wrapped.grow() }</font></div><div class=""><font face="monospace, monospace" class=""> init<W: Farm> (_ x: W) where W.Produce == V {</font></div><div class=""><font face="monospace, monospace" class=""> wrapped = _AnyFarmBox(x)</font></div><div class=""><font face="monospace, monospace" class=""> }</font></div><div class=""><font face="monospace, monospace" class="">}</font></div></div><div class=""><br class=""></div><div class=""><br class=""></div><div class="">There is one little hiccough when you need an initializer in the abstract base class, which you can read about <a href="https://www.bignerdranch.com/blog/breaking-down-type-erasures-in-swift/" class="">here</a> among other places.</div><div class=""><br class=""></div><div class="">Hope that helps,</div><div class=""><br class=""></div><div class="">Nevin</div><div class=""><br class=""></div></div><div class="gmail_extra"><br class=""><div class="gmail_quote">On Sun, Jul 16, 2017 at 12:32 AM, Glen Huang via swift-users <span dir="ltr" class=""><<a href="mailto:swift-users@swift.org" target="_blank" class="">swift-users@swift.org</a>></span> wrote:<br class=""><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">This sounds like the right approach!<br class="">
<br class="">
However, as I experimented with AnyHashable more, I found out that after converting a concrete type to it, I could still convert back using “as”:<br class="">
<br class="">
AnyHashable(Foo()) as! Foo<br class="">
<br class="">
I guess that’s not the case with AnyNamed? I tried to imitate AnyHashable:<br class="">
<br class="">
struct AnyNamed: Named {<br class="">
let base: Any<br class="">
<span class=""> init<T: Named>(_ value: T) {<br class="">
</span> base = value<br class="">
}<br class="">
<br class="">
var name: String {<br class="">
// How do I convert `base` to `Named` here?<br class="">
}<br class="">
}<br class="">
<br class="">
But I have no idea what to put in `var name: String`. Also, even if we managed to come up with a solution, would it magically allow direct casting with “as”? Does the complier do something special for AnyHashable?<br class="">
<div class="HOEnZb"><div class="h5"><br class="">
<br class="">
> On 16 Jul 2017, at 12:58 AM, Ole Begemann <<a href="mailto:ole@oleb.net" class="">ole@oleb.net</a>> wrote:<br class="">
><br class="">
> One way to do this in Swift is a method called type erasure.<br class="">
><br class="">
> Type erasure means you create a new type that wraps any value whose concrete type you want to erase. This new type also conforms to the protocol. By convention the type is named Any... (compare AnyIterator and AnySequence in the standard library, which do the same thing).<br class="">
><br class="">
> struct AnyNamed: Named {<br class="">
> private let _name: () -> String<br class="">
><br class="">
> init<T: Named>(_ value: T) {<br class="">
> _name = { <a href="http://value.name/" rel="noreferrer" target="_blank" class="">value.name</a> }<br class="">
> }<br class="">
><br class="">
> var name: String {<br class="">
> return _name()<br class="">
> }<br class="">
> }<br class="">
><br class="">
> AnyNamed is initialized with a generic value T: Named. Notice that the initializer is generic, but the type itself isn't. Because AnyNamed can't store value: T directly (then it would have to be generic over T), we create a closure over <a href="http://value.name/" rel="noreferrer" target="_blank" class="">value.name</a> and store that instead.<br class="">
><br class="">
> Now we can create a Set<AnyNamed> and, because AnyNamed conforms to Named, treat the set's elements as values conforming to Named:<br class="">
><br class="">
> var set = Set<AnyNamed>()<br class="">
> set.insert(AnyNamed(Foo()))<br class="">
> set.insert(AnyNamed(Bar()))<br class="">
><br class="">
> for element in set {<br class="">
> print(<a href="http://element.name/" rel="noreferrer" target="_blank" class="">element.name</a>)<br class="">
> print(element.hashValue)<br class="">
> }<br class="">
><br class="">
><br class="">
> On 11.07.2017 12:10, Glen Huang via swift-users wrote:<br class="">
>> Hi,<br class="">
>><br class="">
>> I want to store some heterogeneous items all conform to a protocol inside a set, is it something possible to do in swift?<br class="">
>><br class="">
>> I tried this example:<br class="">
>><br class="">
>> ```<br class="">
>> protocol Named: Hashable {<br class="">
>> var name: String { get }<br class="">
>> }<br class="">
>><br class="">
>> extension Named {<br class="">
>> var hashValue: Int {<br class="">
>> return name.hashValue<br class="">
>> }<br class="">
>><br class="">
>> static func ==(lhs: Self, rhs: Self) -> Bool {<br class="">
>> return <a href="http://lhs.name/" rel="noreferrer" target="_blank" class="">lhs.name</a> == <a href="http://rhs.name/" rel="noreferrer" target="_blank" class="">rhs.name</a><br class="">
>> }<br class="">
>> }<br class="">
>><br class="">
>> struct Foo: Named {<br class="">
>> var name = "foo"<br class="">
>> }<br class="">
>><br class="">
>> struct Bar: Named {<br class="">
>> var name = "bar"<br class="">
>> }<br class="">
>><br class="">
>> var item = Set<Named>()<br class="">
>> item.insert(Foo())<br class="">
>> item.insert(Bar())<br class="">
>> ```<br class="">
>><br class="">
>> But it failed at `Set<Named>()` where it complained "Using 'Named' as a concrete type conforming to protocol 'Hashable' is not supported”.<br class="">
>><br class="">
>> 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?<br class="">
>><br class="">
>> My use case is this:<br class="">
>><br class="">
>> I have an object that can contain two sets of other objects:<br class="">
>><br class="">
>> ```<br class="">
>> class Parent {<br class="">
>> var foos: Set<Foo><br class="">
>> var bars: Set<Bar><br class="">
>> }<br class="">
>> ```<br class="">
>><br class="">
>> 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?<br class="">
>><br class="">
>> Thanks.<br class="">
>> ______________________________<wbr class="">_________________<br class="">
>> swift-users mailing list<br class="">
>> <a href="mailto:swift-users@swift.org" class="">swift-users@swift.org</a><br class="">
>> <a href="https://lists.swift.org/mailman/listinfo/swift-users" rel="noreferrer" target="_blank" class="">https://lists.swift.org/<wbr class="">mailman/listinfo/swift-users</a><br class="">
><br class="">
><br class="">
<br class="">
______________________________<wbr class="">_________________<br class="">
swift-users mailing list<br class="">
<a href="mailto:swift-users@swift.org" class="">swift-users@swift.org</a><br class="">
<a href="https://lists.swift.org/mailman/listinfo/swift-users" rel="noreferrer" target="_blank" class="">https://lists.swift.org/<wbr class="">mailman/listinfo/swift-users</a><br class="">
</div></div></blockquote></div><br class=""></div>
</div></blockquote></div><br class=""></div></div></body></html>