The problem is that you promise that the compiler will not be able to prove that you will save.
So, you made this promise: the copy() call will return its own fully initialized type.
But then you implemented copy() as follows:
func copy() -> Self { return C() }
Now I am a subclass that does not override copy() . And I return C , not a fully initialized Self (which I promised). So nothing good. What about:
func copy() -> Self { return Self() }
Well, that doesn't compile, but even if that were the case, it would be nice. A subclass may not have a trivial constructor, so D() may not even be legal. (Although see below.)
OK, how about:
func copy() -> C { return C() }
Yes, but that does not return Self . It returns C You still do not keep your promise.
"But ObjC can do it!" Well, sort of. Mostly because it doesn't matter if you keep your promise, like Swift does. If you do not implement copyWithZone: in a subclass, you can completely not initialize your object. The compiler will not even warn you that you did this.
"But most of everything in ObjC can be translated into Swift, and ObjC has NSCopying ." Yes, and here is how it is defined:
func copy() -> AnyObject!
So you can do the same (no reason for here!):
protocol Copyable { func copy() -> AnyObject }
It says, "I promise nothing that you will return." You can also say:
protocol Copyable { func copy() -> Copyable }
This is a promise you can make.
But we can think a little about C ++ and remember that there is a promise we can make. We can promise that we and all our subclasses will implement certain types of initializers, and Swift will provide this (and therefore can prove that we are telling the truth):
protocol Copyable { init(copy: Self) } class C : Copyable { required init(copy: C) {
Here's how you should make copies.
We can take this step further, but it uses dynamicType , and I have not tested it extensively to make sure that this is always what we want, but it should be correct:
protocol Copyable { func copy() -> Self init(copy: Self) } class C : Copyable { func copy() -> Self { return self.dynamicType(copy: self) } required init(copy: C) {
Here we promise that there is an initializer that executes copies for us, and then at runtime we can determine which one to call by providing us with the syntax of the method you were looking for.