Fast protocol requiring properties as a protocol

I am trying to define a Repository protocol that requires defining several properties (which implement a specific DataSource protocol)

But because of the complexity of my actual scenario, one of these properties should be the DataSource sub-protocol.

I reduced the problem to this simple code:

protocol DataSource { } protocol ExtraDataSouce: DataSource { func method1() -> String } struct MyDataSource: ExtraDataSouce { func method1() -> String { return "whatever" } } protocol Repository { var firstDataSource: DataSource { get } var secondDataSource: DataSource { get } } struct MyRepository: Repository { var firstDataSource: DataSource var secondDataSource: MyDataSource } 

Which return an error at compile time because "MyRepository" does not match the "repository". But I think it really is ... Any idea on why it does not accept "secondDataSource" in "MyRepository" defined as "MyDataSource"?

+2
source share
2 answers

After searching, I found this information about your question (please correct me if I am mistaken somewhere or if I miss something):

Even if your code should work logically, the fast compiler does not separate cases when you use regular or readable protocol variables when declaring their type in the MyRepository class. In other words, a bug in the code becomes apparent if you write in the Repository

 var secondDataSource: DataSource { get set } 

and the compiler does not separate this case. I have not found the absolutely correct way to do what you want. But there are two close ways:

1) The obvious and probably the most correct way is to change the secondDataSource type in MyRepository and use an additional variable if you want:

 var _secondDataSource: MyDataSource var secondDataSource: DataSource { get {return _secondDataSource} set { guard let newValue = newValue as? MyDataSource else { fatalError("MyRepository: attempt to set DataSource type, MyDataSource type expected") } _secondDataSource = newValue } } 

2) Associated type by protocol. Here I will improve @RaduNunu's answer, since the string associatedtype type = DataSource in its code only has a placeholder effect, and its solution allows you to select any type of secondDataSource ever, String , for example:

 protocol Repository { associatedtype Type = DataSource var firstDataSource: DataSource { get } var secondDataSource: Type { get } } struct MyRepository: Repository { var firstDataSource: DataSource var secondDataSource: String // - this is ok! } 

This code will compile and work, but it looks pretty bad. Instead, enter a placeholder that uses the protocol better:

 protocol Repository { associatedtype Type: DataSource var firstDataSource: DataSource { get } var secondDataSource: Type { get } } struct MyRepository: Repository { var firstDataSource: DataSource //var secondDataSource: String - this line not allowed now var secondDataSource: MyDataSource } 

This code is already pretty close to the goal. However, from now on, you cannot use the protocol as a related type, so the declaration

 var secondDataSource: DataSource 

MyRepository will not work. This is a fee for using the associated type: you can only use the DataSource corresponding class types / enum / struct.

+2
source

The Repository protocol implements 2 variables of the DataSource type, when you try to change the type of a variable in a structure that corresponds to the repository protocol, it will not allow you to do this because of the required type. You must use a linked type to make this change.

 protocol Repository { associatedtype type = DataSource var firstDataSource: DataSource { get } var secondDataSource: type { get } } 
+1
source

All Articles