Recently while giving an internal talk at The App Business on Type Erasure I noticed myself not really understanding the true nature of Self (so deep) in a Generic Protocol. Through some hugely productive discussion with my co workers I arrived at a greater understanding of how the compiler interprets Self but I still have a long way to go. It all started with this,
protocol SelfExaminer {
func examineInstanceOfSelf(selfInstance: Self) -> Self
}
A rather silly protocol that I was using so I could demonstrate Type Erasure. If you are unfamiliar with Typer erasure check out these awesome blog posts which brilliantly explain the process.
As we know a generic protocol like this will cause me issues if I try to use this protocol as a Type. What I found interesting is the following protocol does not cause me any problems when I try to use it as a Type.
func examineInstanceOfSelf(selfInstance: Int) -> Self
We still have a generic Self requirement but suddenly swift no longer complains. If we take our original protocol and try to use a function we can see why this causes problems very clearly
protocol SelfExaminer {
func examineInstanceOfSelf(selfInstance: Self) -> Self
}
func someFunction(examiner: SelfExaminer) {
examiner.examineInstanceOfSelf(????)
}
What I struggle to understand is why Swift is totally ok with the following
protocol SelfExaminer {
func examineInstanceOfSelf(selfInstance: Int) -> Self
}
func someFunction(examiner: SelfExaminer) {
let someSelfExaminer = examiner.examineInstanceOfSelf(4)
}
Surely now we don't know the type of someSelfExaminer, if we look at it in the editor we can see that it has a Self Examiner type.
This took me a little time to wrap my head around but it makes sense as in this context you will only ever be able to treat it as a SelfExaminer. With input parameters this is obviously far less acceptable as the function would expect a full implementation of Self.