Overriding a stored property in Swift

99,440

Solution 1

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()

print(j1.lightSaberColor)
print(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

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

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

Solution 4

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

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.

Share:
99,440
cfischer
Author by

cfischer

Updated on July 08, 2022

Comments

  • cfischer
    cfischer almost 2 years

    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?

  • Max MacLeod
    Max MacLeod over 8 years
    same applies as per comment above
  • DimaSan
    DimaSan about 7 years
    While this code snippet may solve the question, including an explanation really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion.
  • Sergey Kalinichenko
    Sergey Kalinichenko almost 7 years
    @MaxMacLeod Apart from observers, stored properties do not have behavior, so there is really nothing there to override. He wanted to give a stored property a different value in the subclass, but he was unsure about the mechanism to achieve it. The answer explains how it can be done in Swift. I'm sorry for the late reply, it appears that your comment causes enough confusion to attract downvotes, so I decided to explain what is going.
  • Massimo Pavanel
    Massimo Pavanel almost 3 years
    init() on subclass of UIViewController just sit on viewDidLoad
  • ggbranch
    ggbranch over 2 years
    This does not provide an answer to the question. Once you have sufficient reputation you will be able to comment on any post; instead, provide answers that don't require clarification from the asker. - From Review
  • Admin
    Admin over 2 years
    As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.