Karim Stekelenburg
Karim Stekelenburg

Reputation: 643

Defining multiple typealiasses

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

Answers (3)

dmlebron
dmlebron

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

matt
matt

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

Sergio Andreotti
Sergio Andreotti

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

Related Questions