Reputation: 70
I'm trying to use a protocol with associated type as return value of a class func.
Another post here on stackoverflow is about the same question and based on this post's answer I tried the following:
// addArg takes a single Int argument and returns something,
// which is capable of adding a another Int argument
class OpWithNoArg {
func addArg<OP: OpWithOneArg where OP.ArgType == Int>(arg: Int) -> OP {
return OpWithOneArgImpl() // (1) error here !
}
}
// a protocol with associated type, which allows adding another
// argument of a not yet specified type
protocol OpWithOneArg {
typealias ArgType
func addAnotherArg(arg: ArgType)
}
// an implementation of the protocol above,
// which fixes the associated type to an Int
class OpWithOneArgImpl : OpWithOneArg {
typealias ArgType = Int
func addAnotherArg(arg: Int) {
// ...
}
}
The error in Xcode 7.0 Beta 4 on line marked with (1) is
cannot convert return expression of type 'OpWithOneArgImpl' to expected return type 'OP'
If I change the return value to an optional and nil
is returned, the sample compiles successfully:
// return null
class OpWithNoArg {
func addArg<OP: OpWithOneArg where OP.ArgType == Int>(arg: Int) -> OP? {
// return OpWithOneArgImpl()
return nil
}
}
Is this way of using a protocol with associative type as return value possible in swift, and if that's the case, how can the compiler error mentioned above be fixed?
Thanks in advance!
EDIT:
In Java, the code would be something like the following snippet. I try to find a way in Swift to achieve the same.
class C {
<T> P<T> f(T arg) {
return new PImpl();
}
}
interface P<S> {
void g(S arg);
}
class PImpl<S> implements P<S> {
PImpl() {}
public void g(S arg) {}
}
Upvotes: 0
Views: 1589
Reputation: 6726
Not clear what you are trying to achieve, but imho the error stems from the fact that in your addArg
function you define a generic type OP
which should be typically used in the function's arguments and body.
Instead you return a non generic type trying to force it to be treated as a generic `OP.
A quick fix could be a force cast to OP
of your return object:
return OpWithOneArgImpl() as !OP
but I wouldn't recommend it.
In your example your addArg
will always return a OpWithOneArgImpl
thus it could just be defined as a func addArg(arg: Int) -> OpWithOneArgImpl
Hope this helps.
EDIT:
Probably this is not what you're trying to achieve, but hope it can help with a clearer explanation of what I intended above.
protocol OpWithOneArg {
typealias ArgType
func addAnotherArg(arg: ArgType)
init() // Must have a init with no argument
}
class OpWithOneArgImpl : OpWithOneArg {
typealias ArgType = Int
func addAnotherArg(arg: Int) {
// ...
}
required init() {
// init implementation
}
}
class OpWithNoArg {
func addArgWithOPType<OP: OpWithOneArg where OP.ArgType == Int>(op: OP.Type, arg: Int) -> OP {
return OP() // Here we use the init
}
}
let foo = OpWithNoArg()
foo.addArgWithOPType(OpWithOneArgImpl.self, arg: 3)
Edit:
Maybe you might investigate the use of generic types:
protocol OpWithOneArg {
typealias ArgType
func addAnotherArg(arg: ArgType)
init() // Must have a init with no argument
}
class OpWithOneArgImpl<T> : OpWithOneArg { // Generic implementation confirming to protocol
typealias ArgType = T
func addAnotherArg(arg: T) {
// ...
}
required init() {
// init implementation
}
}
class OpWithNoArg {
func addArgWithOPType<OP: OpWithOneArg>(op: OP.Type, arg: OP.ArgType) -> OP {
return OP() // Here we use the init
}
}
let foo = OpWithNoArg()
// OpWithOneArgImpl<Int>
foo.addArgWithOPType(OpWithOneArgImpl.self, arg: 3)
// OpWithOneArgImpl<String>
foo.addArgWithOPType(OpWithOneArgImpl.self, arg: "Hello")
Upvotes: 2