This is a valid protocol declaration in Swift:
protocol Proto1: class {
func method1() -> Self
func method2() -> [Proto1]
}
But this isn't:
protocol Proto2: class {
func method1(param: Self)
func method2() -> [Proto2]
}
The error message is:
Protocol 'Proto2' can only be used as a generic constraint because it has Self or associated type requirements
So it seems that, when using Self
as function's return type, Swift doesn't consider that as a constraint of the protocol being defined and hence it's OK to use the protocol itself as functions' return type. But when using Self
as function's parameter type, the behavior is completely different.
I wonder why such a difference?
Because it's not useful to have a Self
as a parameter type of a method. Suppose that you can do:
protocol P {
func f(_ x: Self)
}
class A: P {
func f(_ x: Self) {
// not relevant
}
}
class B: A { }
Now suppose I have:
func g(x: A) {
// what can I do with x?
}
The fact is, there is no way to call x.f
. Because I can pass an instance of B
to x
, in which case x.f
would accept a B
instead. x
could be an instance of any subclass of A
that I have no way of knowing at compile time, so I don't know what I can pass to x.f
.
Compare that to Self
used as the return type:
protocol P {
func f() -> Self
}
// Implementation:
class A: P {
func f() -> Self {
self
}
}
class B: A { }
func g(x: A) {
let foo: A = x.f()
}
Here, we know that I can at least assign the return value of x.f
to a variable of type A
. Even if x
is an instance of B
, which means that f
returns a B
, we can still assign that to a variable of type A
.