Overriding a stored property in Swift

InheritanceSwiftPropertiesOverriding

Inheritance Problem Overview


I noticed that the compiler won't let me override a stored property with another stored value (which seems odd):

class Jedi {
    var lightSaberColor = "Blue"
}


class Sith: Jedi {
    override var lightSaberColor = "Red" // Cannot override with a stored property lightSaberColor
}

However, I'm allowed to do this with a computed property:

class Jedi {
    let lightSaberColor = "Blue"
}


class Sith: Jedi {
    override var lightSaberColor : String{return "Red"}

}

Why am I not allowed to give it another value?

Why is overriding with a stored property an abomination and doing it with a computed one kosher? What where they thinking?

Inheritance Solutions


Solution 1 - Inheritance

> Why am I not allowed to just give it another value?

You are definitely allowed to give an inherited property a different value. You can do it if you initialize the property in a constructor that takes that initial value, and pass a different value from the derived class:

class Jedi {
    // I made lightSaberColor read-only; you can make it writable if you prefer.
    let lightSaberColor : String
    init(_ lsc : String = "Blue") {
        lightSaberColor = lsc;
    }
}

class Sith : Jedi {
    init() {
        super.init("Red")
    }
}

let j1 = Jedi()
let j2 = Sith()

println(j1.lightSaberColor)
println(j2.lightSaberColor)

Overriding a property is not the same as giving it a new value - it is more like giving a class a different property. In fact, that is what happens when you override a computed property: the code that computes the property in the base class is replaced by code that computes the override for that property in the derived class.

> [Is it] possible to override the actual stored property, i.e. lightSaberColor that has some other behavior?

Apart from observers, stored properties do not have behavior, so there is really nothing there to override. Giving the property a different value is possible through the mechanism described above. This does exactly what the example in the question is trying to achieve, with a different syntax.

Solution 2 - Inheritance

For me, your example does not work in Swift 3.0.1.

I entered in the playground this code:

class Jedi {
    let lightsaberColor = "Blue"
}

class Sith: Jedi {
    override var lightsaberColor : String {
        return "Red"
    }
}

Throws error at compile time in Xcode: > cannot override immutable 'let' property 'lightsaberColor' with the getter of a 'var'

No, you can not change the type of stored property. The Liskov Substitution Principle forces you to allow that a subclass is used in a place where the superclass is wanted.

But if you change it to var and therefore add the set in the computed property, you can override the stored property with a computed property of the same type.

class Jedi {
	var lightsaberColor = "Blue"
}


class Sith: Jedi {
	override var lightsaberColor : String {
		get {
			return "Red"
		}
		set {
			// nothing, because only red is allowed
		}
	}
}

This is possible because it can make sense to switch from stored property to computed property.

But override a stored var property with a stored var property does not make sense, because you can only change the value of the property.

You can, however, not override a stored property with a stored property at all.


I would not say Sith are Jedi :-P. Therefore it is clear that this can not work.

Solution 3 - Inheritance

class SomeClass {
    var hello = "hello"
}
class ChildClass: SomeClass {
    override var hello: String {
        set {
            super.hello = newValue
        }
        get {
            return super.hello
        }    
    }
}

Solution 4 - Inheritance

You probably want to assign another value to the property:

class Jedi {
    var lightSaberColor = "Blue"
}


class Sith: Jedi {
    override init() {
        super.init()
        self.lightSaberColor = "Red"
    }
}

Solution 5 - Inheritance

For Swift 4, from Apple's documentation:

> You can override an inherited instance or type property to provide > your own custom getter and setter for that property, or to add > property observers to enable the overriding property to observe when > the underlying property value changes.

Solution 6 - Inheritance

If you attempt to do that in Swift 5 you will be greeted by a

> Cannot override immutable 'let' property 'lightSaberColor' with the getter of a 'var'

Your best bet is to declare it as a computed property.

This works as we are just overriding the get {} function

class Base {
   var lightSaberColor: String { "base" }
}

class Red: Base {
   override var lightSaberColor: String { "red" }
}

Solution 7 - Inheritance

In Swift, this is unfortunately not possible to do. The best alternative is the following:

class Jedi {
    private(set) var lightsaberColor = "Blue"
}


class Sith: Jedi {
    override var lightsaberColor : String {
        get {
            return "Red"
        }
    }
}

Solution 8 - Inheritance

Swift does not allow you to override a variable stored property Instead of this you can use computed property

class A {
    var property1 = "A: Stored Property 1"

    var property2: String {
        get {
            return "A: Computed Property 2"
        }
    }

    let property3 = "A: Constant Stored Property 3"

    //let can not be a computed property
    
    func foo() -> String {
        return "A: foo()"
    }
}

class B: A {

    //now it is a computed property
    override var property1: String {

        set { }
        get {
            return "B: overrode Stored Property 1"
        }
    }

    override var property2: String {
        get {
            return "B: overrode Computed Property 2"
        }
    }
    
    override func foo() -> String {
        return "B: foo()"
    }

    //let can not be overrode
}
func testPoly() {
    let a = A()
    
    XCTAssertEqual("A: Stored Property 1", a.property1)
    XCTAssertEqual("A: Computed Property 2", a.property2)
    
    XCTAssertEqual("A: foo()", a.foo())
    
    let b = B()
    XCTAssertEqual("B: overrode Stored Property 1", b.property1)
    XCTAssertEqual("B: overrode Computed Property 2", b.property2)
    
    XCTAssertEqual("B: foo()", b.foo())
    
    //B cast to A
    XCTAssertEqual("B: overrode Stored Property 1", (b as! A).property1)
    XCTAssertEqual("B: overrode Computed Property 2", (b as! A).property2)
    
    XCTAssertEqual("B: foo()", (b as! A).foo())
}

It is more clear when compare with Java, where a class field can not be overrode and does not support polymorphism because is defined in compile time(run efficiently). It is called a variable hiding[About] It is not recommended to use this technics because it is hard to read/support

[Swift property]

Solution 9 - Inheritance

I had the same problem to set a constant for a view controller.

As I'm using interface builder to manage the view, I cannot use init(), so my workaround was similar to other answers, except I used a read-only computed variable on both base and inherited classes.

class Jedi {
	var type: String {
		get { return "Blue" }
	}
}

class Sith: Jedi {
	override var type: String {
		get { return "Red" }
	}
}

Solution 10 - Inheritance

You also can use a function to override. It's not direct answer, but can enrich this topic)

Class A

override func viewDidLoad() {
    super.viewDidLoad()

    if shouldDoSmth() {
       // do
    }
}

public func shouldDoSmth() -> Bool {
    return true
}

Class B: A

public func shouldDoSmth() -> Bool {
    return false
}

Solution 11 - Inheritance

additional to above examples,

class SomeClass {
    var hello = "hello"
}
class ChildClass: SomeClass {
    override var hello: String {
        set {
            _hello = newValue
        }
        get {
            _hello
        }   
    }
    private var _hello: String = ""
}


// Testing...
let c = ChildClass()
c.hello = "test"
print(c.hello) // test

Solution 12 - Inheritance

    //declaring class
class Games {
       var  no_player:Int = 0
        var name_game :String = ""
        var player_value:String {
            return "low"
        }
        func playing(){
            print( "the \(name_game) is played by \(no_player) players and the player value is \(player_value)")
        }
    }
//chess class inherits Games
    class Chess : Games {
        var location:String = ""
    }
//cricket class inherits Games
    class cricket : Games{
        var ball_brand = "sg"
    }
    //making object of Chess()
     let Chess1 = Chess()
    Chess1.name_game = "Chess "
    Chess1.no_player = 2
    Chess1.palying()
//polo inherits Games

    class polo:Games {
        override var player_value: String{
            return "high"
        }
        
        override func playing() {
            print("holla we are playing cricket with 10 members and the palyer value is  \(player_value) ")
        }
    }
    var polo1 = polo()
    polo1.playing()

Solution 13 - Inheritance

I use this approach:

class Class {
	
	private lazy var _instance: AType = {
		return AType()
	} ()
	
	var instance: AType {
		return _instance
	}
	
}

class Subclass: Class {
	
	private lazy var _instance: AType = {
		return ASubType()
	} ()
	
	override var instance: AType {
		return _instance
	}
	
}

Solution 14 - Inheritance

You can use this method to update the values

class A {

    var lightSaberColor : String = "Red"
}

You don't need to override variables. You can change the value of the variable.

class B: A {
     * **Change Value when the class will initialize.**

     override init() {
        super.init()
          self.lightSaberColor = "Orange"
     }

    /*
     * **Change Value when you will use this function.**
     */
    func test() {
       lightSaberColor = "Green"
    }
}

let b = B()

b.test()

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestioncfischerView Question on Stackoverflow
Solution 1 - InheritanceSergey KalinichenkoView Answer on Stackoverflow
Solution 2 - InheritanceBinarianView Answer on Stackoverflow
Solution 3 - InheritanceZhiping YangView Answer on Stackoverflow
Solution 4 - InheritancezisoftView Answer on Stackoverflow
Solution 5 - InheritanceriyasavlaView Answer on Stackoverflow
Solution 6 - InheritanceHugo AlonsoView Answer on Stackoverflow
Solution 7 - InheritanceNoah WilderView Answer on Stackoverflow
Solution 8 - InheritanceyoAlex5View Answer on Stackoverflow
Solution 9 - InheritanceYassine ElBadaouiView Answer on Stackoverflow
Solution 10 - InheritanceNike KovView Answer on Stackoverflow
Solution 11 - InheritanceOguzYukselView Answer on Stackoverflow
Solution 12 - InheritanceHritik SinghView Answer on Stackoverflow
Solution 13 - InheritanceVictor_ZView Answer on Stackoverflow
Solution 14 - InheritanceMuhammad AsherView Answer on Stackoverflow