Reputation: 643
While experimenting with generics in Swift I came across this problem and am not able to find an answer.
Say I have the following code:
protocol Component {
}
protocol Contains {
associatedtype CompType: Component
var components: [CompType] { get set }
}
Here, types that implement Contains
should be able to store any type that implements the Component
protocol specified by their typealias. If I extend the code to the following, it works as expected.
protocol Component {
}
struct SomeComponent: Component {
init() {
}
}
struct AnotherComponent: Component {
init() {
}
}
protocol Contains {
associatedtype CompType: Component
var components: [CompType] { get set }
}
struct Container: Contains {
typealias CompType = SomeComponent
var components: [SomeComponent]
}
var x = Container(components: [SomeComponent()]) // works perfectly!
var y = Container(components: [AnotherComponent()]) // fails as expected
Finally the question: is it possible to make Container.components
accept both SomeComponent
and AnotherComponent
, but reject other types that implement the Component
protocol? In other words, can typealias
hold more that one type?
Thanks!
Upvotes: 0
Views: 600
Reputation: 861
I don't think you need the associatedtype
at all
protocol Component {
}
struct SomeComponent: Component {
init() {
}
}
struct AnotherComponent: Component {
init() {
}
}
protocol Contains {
var components: [Component] { get set }
}
struct Container: Contains {
var components: [Component]
}
var x = Container(components: [SomeComponent()])
var y = Container(components: [AnotherComponent()])
Use associatedtype
on protocols when you need to specify a type.
On this case you don't want to specify because you want to be able to accept a conformer to a protocol
Upvotes: 0
Reputation: 535222
The type alias serves to resolve the generic associated type. It must resolve it to one type unambiguously; that is what resolution is.
Well, the way you’ve set things up, that type can and must be any Component adopter. That is what this line means:
associatedtype CompType: Component
You used a generic constraint of Component. If that’s not what you wanted, you shouldn’t have set things up that way. As others have suggested, if you want just SomeComponent and AnotherComponent to satisfy the generic constraint, then you would need to use a protocol that only SomeComponent and AnotherComponent adopt.
Upvotes: 0
Reputation: 923
You can conform to multiple protocols
typealias CompType = SomeComponent & AnotherComponent
Or you can do changing logic
protocol Component {
}
struct SomeComponent: Component {
init() {
}
}
struct AnotherComponent: Component {
init() {
}
}
protocol Contains {
var components: [Component] { get set }
}
struct Container: Contains {
var components: [Component]
}
var x = Container(components: [SomeComponent()])
var y = Container(components: [AnotherComponent()])
Upvotes: 2