1

Here's an example of a good old fashion single inheritance OO class tree:

class Common {
    var foo:String = ""
    var bar:Int = 0
    // common behavior to deal with foo + bar
}

class SubA:Common {
    var yak:Double = 0.0
    // specialized behavior to deal with yak, foo, and bar
}

class SubB:Common {
    var baz:CGFloat = 1.0
    // specialized behavior to deal with baz, foo, and bar
}

Pretty straightforward. Swift gives us lots of new ways to think about things, but this is still a very common OO paradigm and often worthwhile to use. If I want to create ViewControllers that interact with these, it's tempting to follow the same pattern:

class CommonViewController:UIViewController {
    var model:Common!
    // common behavior to deal with the common behavior found in the Common superclass
}

class SubAViewController:CommonViewController {
    var model:SubA!
    // more methods to deal with the specializations that SubA provides
}

class SubBViewController:CommonViewController {
    var model:SubB!
    // more methods to deal with the specializations that SubA provides
}

Again, pretty standard construct. Unfortunately, Swift's type system will not allow it:

error: cannot override mutable property 'model' of type 'Common!' with covariant type 'SubA!'
    var model:SubA!

Is there an easy to solve this? The simplest I could think of is to do the sub ViewControllers as:

class SubAViewController:CommonViewController {
    var subA:SubA {
        get {
            return self.model as! SubA
        }
        set {
            self.model = newValue
        }
    }
    // some behavior will need to use self.subA to get that type of data
}

class SubBViewController:CommonViewController {
    var subB:SubB {
        get {
            return self.model as! SubB
        }
        set {
            self.model = newValue
        }
    }
    // some behavior will need to use self.subA to get that type of data
}

This adds 2 had-to-do-this-to-make-it-work methods and the constraint that some of my subclass methods will have to refer to self.subB or self.subA rather than self.model. I started working through how to do this with protocols and extensions, but I just felt like I was adding more and more hoops to make the solution be what I wanted. Is there a simpler solution that one can use with Swift to implement this very classic and common OO inheritance pattern?

Travis Griggs
  • 21,522
  • 19
  • 91
  • 167

2 Answers2

1

In short you cannot do it this way. You must add a new property with the different type and provide getter and setter the the one that is overridden. Similar case can be found here: Overriding superclass property with different type in Swift

Community
  • 1
  • 1
anakin
  • 551
  • 4
  • 12
1

What you are trying to do is not permitted in any strongly and statically typed object oriented language, not only in Swift.

Consider for instance a function f that gets an object of type CommonViewController. This function could for example modify the object's variable model with a new value, instance of class Common.

Then, you could pass to f a value of type SubAViewController, which would be legal, since its type would be a subtype of CommonViewController. When f assigns to its attribute model a new value of type Common, this violates the type declaration of model inside SubAViewController, and this could cause a run-time type error, which is not allowed in this kind of languages.

Renzo
  • 26,848
  • 5
  • 49
  • 61