Specialize general function requirement for protocol inheritance

I have some protocol hierarchies in my code where I have protocols defining the objects I use and protocols defining functions to use with these objects.

Object protocols are inherited by other object protocols, which add additional functions to the original protocols, as well as functions that use them. The problem is that I cannot find a way to specialize the function to take only the inherited parameter.

Here is some code to clarify what I'm trying to do:

protocol A { var foo: String { get set } } protocol B: A { var bar: String { get set } } struct Test: B { var foo: String = "foo" var bar: String = "bar" } protocol UseAProtocol { static func use<T: A>(_ obj: T) } protocol UseBProtocol: UseAProtocol { } extension UseBProtocol { //If I change the requirement to <T: B> this won't conform to `UseAProtocol`. static func use<T: A>(_ obj: T) { print(obj.foo) // print(obj.bar) - Since obj does not conform to `B` I can't access ".bar" here without a forced casting. } } struct Manager: UseBProtocol { } Manager.use(Test()) 

I want to make use function on UseBProtocol accept only objects matching B B inherits from A , but when I change from <T:A> to <T:B> , I got an error saying that the Manager does not match UseAProtocol and I need to change it to <T:A> .

I know that I can do this using the associatedtype and where clauses for inheritance protocols - what I'm using today - but I wanted to move the general requirement for the method so that I can combine all of them together in (I have a lot of these hierarchies, and using associatedtype I have to use one structure in a hierarchy). When conditional matches came to Swift, this would be possible with an associatedtype , but as long as they ...

I could also use as! to force casting from A to B in the implementation of UseBProtocol , but this is a really bad decision, and the error will be thrown only at runtime.

Is there any way to achieve what I'm looking for?

+5
source share
1 answer

It seems that you are really looking for associatedType in UseAProtocol , and not for creating a use function.

UseAProtocol declaring the associated type in UseAProtocol and changing the signature of the use function to static func use(_ obj: ProtocolType) , your code compiles fine, and you can access foo and bar from Manager .

 protocol AProtocol { var foo: String { get set } } protocol BProtocol: AProtocol { var bar: String { get set } } struct Test: BProtocol { var foo: String = "foo" var bar: String = "bar" } protocol UseAProtocol { associatedtype ProtocolType static func use(_ obj: ProtocolType) } protocol UseBProtocol: UseAProtocol { } extension UseBProtocol { static func use(_ obj: BProtocol) { print(obj.foo) print(obj.bar) } } struct Manager: UseBProtocol { } Manager.use(Test()) //prints both "foo" and "bar" 
0
source

Source: https://habr.com/ru/post/1274863/


All Articles