Search code examples
swiftclonesubclasssuperclass

Getting clone of superclass


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.


Solution

  • 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.