0

Here is my playground snippet:

class Box {
  func clone() -> Box {
    return Box() // <- how to return superclass here?
  }
}

class VBox:Box { }

let vb = VBox()
let cBox = vb.clone() // now cBox is a Box, not a VBox

My clone function returns a Box class in all cases. But for the subclass I want it to return the superclass (so above it should return VBox).

I know I could override the clone function inside VBox but I wonder if there's a smarter way.

qwerty_so
  • 35,448
  • 8
  • 62
  • 86
  • 3
    VBox is a *subclass* of Box, not a superclass. – This might be what you are looking for: [Protocol func returning Self](http://stackoverflow.com/questions/25645090/protocol-func-returning-self) – Martin R Mar 01 '15 at 15:45
  • Got the flu any my brain still feel hazy. You are right. So it looks like I need to make them NSObject and use NSCopying? - Ehrm. You changed the link on the fly? – qwerty_so Mar 01 '15 at 15:50
  • *"Ehrm. You changed the link on the fly"* – Yes. – Martin R Mar 01 '15 at 15:53
  • 1
    `NSCopying` is not the right tool for that. It is unsafe since it has to cast through `AnyObject`. `NSCopying` should only be used to interact with Cocoa. The right tool is to implement `init(copy:)`. – Rob Napier Mar 01 '15 at 16:00

1 Answers1

3

You mean subclass. Box is the superclass, which is what you're returning.

This is very similar to the following:

It's not exactly the same question, though, since you're dealing with classes rather than protocols, so we can go through that example. First, the right tool is init, not a clone:

class Box {
    let a: String
    init(_ a: String) { self.a = a }
    convenience init(copy: Box) { self.init(copy.a) }
}

class VBox:Box {}

let vb = VBox("test")
let cBox = VBox(copy: vb)

You see that this works fine since VBox adds no additional properties. But if VBox does add additional properties, then you'll get all the right errors that require you to implement an init.

class Box {
    let a: String
    init(_ a: String) { self.a = a }
    convenience init(copy: Box) { self.init(copy.a) }
}

class VBox:Box {
    let b: String
    init(_ a: String, _ b: String) {
        self.b = b
        super.init(a)
    }
    convenience init(copy: VBox) {
        self.init(copy.a, copy.b)
    }
}

let vb = VBox("test", "this")
let cBox = VBox(copy: vb)

Note how this prevents you from trying to copy a Box into a VBox (since that would not initialize all the parameters). If you want that to work, you'd need to provide a copy(Box) initializer. This is the nice thing about using init. It keeps track of all the rules for you. NSCopying would let you make that mistake and would eventually crash.

Community
  • 1
  • 1
Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • Sorry for the super/sub confusion (flu, see above comment :-) Martin's first comment led me to some NSObject thread. Later he edited it so it points to the first of your own links above (which I read meanwhile). Thanks for taking the time to adopt it to my needs. Much appreciated! – qwerty_so Mar 01 '15 at 16:12