Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 434
erudel Avatar asked Oct 24 '14 06:10

erudel


People also ask

What is an array of objects in JavaScript?

An array that conations class type elements are known as an array of objects. It stores the reference variable of the object. Before creating an array of objects, we must create an instance of the class by using the new keyword.

How to access the data in an array of objects randomly?

In an array of objects, the data can be accessed randomly by using the index number. Reduce the time and memory by storing the data in a single variable. Writing code in comment?

What is the use of array in C++?

They can be used to store the collection of primitive data types such as int, float, double, char, etc of any particular type. To add to it, an array in C/C++ can store derived data types such as structures, pointers, etc.


1 Answers

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.

like image 57
Antonio Avatar answered Sep 19 '22 22:09

Antonio