This sounds like the right approach!
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”:
AnyHashable(Foo()) as! Foo
I guess that’s not the case with AnyNamed? I tried to imitate AnyHashable:
struct AnyNamed: Named {
let base: Any
init<T: Named>(_ value: T) {
base = value
}
var name: String {
// How do I convert `base` to `Named` here?
}
}
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?
> On 16 Jul 2017, at 12:58 AM, Ole Begemann <[email protected]> wrote:
>
> One way to do this in Swift is a method called type erasure.
>
> 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).
>
> struct AnyNamed: Named {
> private let _name: () -> String
>
> init<T: Named>(_ value: T) {
> _name = { value.name }
> }
>
> var name: String {
> return _name()
> }
> }
>
> 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 value.name and store that instead.
>
> Now we can create a Set<AnyNamed> and, because AnyNamed conforms to Named,
> treat the set's elements as values conforming to Named:
>
> var set = Set<AnyNamed>()
> set.insert(AnyNamed(Foo()))
> set.insert(AnyNamed(Bar()))
>
> for element in set {
> print(element.name)
> print(element.hashValue)
> }
>
>
> On 11.07.2017 12:10, Glen Huang via swift-users 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
>> [email protected]
>> https://lists.swift.org/mailman/listinfo/swift-users
>
>
_______________________________________________
swift-users mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-users