erudel
erudel

Reputation: 480

How to define an array of objects conforming to a protocol?

Given:

protocol MyProtocol {
    typealias T
    var abc: T { get }
}

And a class that implements MyProtocol:

class XYZ: MyProtocol {
    typealias T = SomeObject
    var abc: T { /* Implementation */ }
}

How can I define an array of objects conforming to MyProtocol?

var list = [MyProtocol]()

Gives (together with a ton of SourceKit crashes) the following error:

Protocol 'MyProtocol' can only be used as a generic constraint because it has Self or associated type requirements

Even though the typealias is in fact defined in MyProtocol.

Is there a way to have a list of object conforming to a protocol AND having a generic constraint?

Upvotes: 8

Views: 1874

Answers (1)

Antonio
Antonio

Reputation: 72760

The problem is about using the generics counterpart for protocols, type aliases. It sounds weird, but if you define a type alias, you cannot use the protocol as a type, which means you cannot declare a variable of that protocol type, a function parameter, etc. And you cannot use it as the generic object of an array.

As the error say, the only usage you can make of it is as a generic constraint (like in class Test<T:ProtocolWithAlias>).

To prove that, just remove the typealias from your protocol (note, this is just to prove, it's not a solution):

protocol MyProtocol {
    var abc: Int { get }
}

and modify the rest of your sample code accordingly:

class XYZ: MyProtocol {
    var abc: Int { return  32 }
}

var list = [MyProtocol]()

You'll notice that it works.

You are probably more interested in how to solve this problem. I can't think of any elegant solution, just the following 2:

  • remove the typealias from the protocol and replace T with AnyObject (ugly solution!!)
  • turn the protocol into a class (but that's not a solution that works in all cases)

but as you may argue, I don't like any of them. The only suggestion I can provide is to rethink of your design and figure out if you can use a different way (i.e. not using typealiased protocol) to achieve the same result.

Upvotes: 3

Related Questions