Reputation: 348
From an external library I've got the following scenario.
The protocol and base class:
protocol P1 {
// P1 Stuff
}
class A {
// A Stuff
}
Then there is an extension, which causes my troubles. It is defined for the combination of types P1
and A
.
extension P1 where Self : A {
public func myDesiredFunc() {
// Do stuff.
}
}
And finally there are the implementations B1
- Bn
, which I use.
class B1 : A, P1 {
}
class B2 : A, P1 {
}
...
In my code I need to put together instances of B-classes and work with them. The problem is, that I need to use the extension func myDesiredFunc()
. So I need somehow define, that the array type is something like [(A & P1)]
and the return type of producing funciton is (A & P1)
as well.
However, with this code:
func createBeeInstance() -> (A & P1) {
if something {
return B1()
} else if something {
return B2()
}
...
}
I'm getting the error:
Non-protocol type 'A' cannot be used within a protocol composition.
Is there a way to say that the return type is a composition of class and protocol? I'm not able to change the scenario because it's an external library.
Upvotes: 1
Views: 1219
Reputation: 15597
One possible solution would be to define a protocol that defines the essential nature of objects of type A
(let's call the new protocol Aable
), and make the A
type conform to it:
class A: Aable {
// A stuff
}
You could then constrain the P1
protocol extension with Aable
instead of A
:
extension P1 where Self : Aable {
func myDesiredFunc() {
// Do stuff.
}
}
That would allow you to use protocol composition for the return type of a function...
func createBeeInstance(useB1: Bool) -> (Aable & P1) {
return useB1 ? B1() : B2()
}
...as well as for the element type of an array:
var things = [Aable & P1]()
for i in 1...5 {
let b = createBeeInstance(useB1: i % 2 == 0)
things.append(b)
}
for thing in things {
thing.myDesiredFunc()
}
Upvotes: 1
Reputation: 5300
Swift 4:
^_^
it's possible now to compose class and protocol in swift 4 so modifying the previous snippets to this should work
class A {
// A Stuff
required init () {}
}
protocol P1 {
// P1 Stuff
}
class B1 : A {}
class B3: P1 {}
class B2 : A, P1 {}
func createBeeInstance<T: P1 & A>(type: T.Type) -> T {
return type.init()
}
var things = [P1 & A]() // still Element has to be P1 as well
let f = createBeeInstance(type: B2.self)
//let f1 = createBeeInstance(type: B1.self) // will error
//let f2 = createBeeInstance(type: B3.self) // will error
things.append(f) // is fine
--- OLD Way which did not work ---
You may use this way , having the Sample you provided with modifying class A to have init
class A {
// A Stuff
required init () {}
}
modifying createBee method to
func createBeeInstance<T: P1>(type: T.Type) -> T where T: A {
return type.init()
}
this way you will provide the type as an input e.g. B1.self
for array we can provide typealieased generic
typealias B<T:P1> = T where T: A
var things = [B<A>]() // still Element has to be P1 as well
let f = createBeeInstance(type: B2.self)
let f1 = createBeeInstance(type: B1.self)
things.append(f)
Upvotes: 1