0

According to swift language guide's Inheritance chapter, I tried to code compuputed peoperty in subclass. When I set newValue to the property of the class's instance, the setter seemed to work, while the property value did not convert into the newValue.

class Vehicle {
    var currentSpeed = 1.0
    var description: String {
        return "The current speed is \(currentSpeed) miles per hour"
    }
    func makeNoise() {
    }
}
class Car: Vehicle {
    var gear = 0
    override var description: String {
        return super.description + " in gear \(gear)"
    }
}
class AutomaticCar: Car {
    override var currentSpeed: Double {
        get {
            return super.currentSpeed
        }
        set {
            gear = Int(newValue/10) + 1
        }
    }
}

let automaticCar = AutomaticCar()
automaticCar.currentSpeed = 12.0
print(automaticCar.currentSpeed)//It prints "1.0"
print(automaticCar.description)//It prints "The current speed is 1.0 miles per hour in gear 2"

The property value of automaticCar.currentSpeed is still "1.0" rather than "12.0", while the instance's gear property seems to effect. I have searched but could't find the answer, what principle leads to this situation?

Further question:

class A {
    var test1 = 1
    var test2 = 2
    var sum: Int {
        get {
            return test1 + test2
        }
        set {
            test1 = newValue - test2
        }
    }
}
var a = A()
print(a.sum)
a.sum = 4
print(a.sum)//It ptints "4"
print(a.test1)//It prints "2"

In this case, I don't need to set the value of new sum property deliberately, What's the differece between two cases?

matt
  • 515,959
  • 87
  • 875
  • 1,141
astost
  • 11
  • 4

2 Answers2

1
class AutomaticCar: Car {
    override var currentSpeed: Double {
        get {
            return super.currentSpeed
        }
        set {
            super.currentSpeed = newValue
            gear = Int(newValue/10) + 1
        }
    }
}

You've just forgotten to set the value of currentSpeed in your overridden setter.

kaileymcd
  • 71
  • 5
  • Alternatively, you could override the `didSet` property observer – `override var currentSpeed: Double { didSet { gear = Int(currentSpeed / 10) + 1 } }`. – Hamish Apr 25 '18 at 14:27
  • Thanx for your help. I want to know that in another situation, why do i not need to set the value of a.sum in my setter? Is something difference between class and subclass? – astost Apr 25 '18 at 14:45
  • @astost You are confusing yourself. It has nothing to do with class vs. subclass. It has to do with stored property vs. computed property. — As Hamish rightly says, this would be a lot simpler and clearer if your `currentSpeed` override were a setter observer instead of a computed property. – matt Apr 25 '18 at 15:02
  • @matt The automaticCar.currentSpeed in first case, and the a.sum in second case are both computed property, but it's necessary to set the value of currentSpeed in setter, while it seems no need for setting the value of sum in setter. I'm confusing about the difference between the two cases in the aspect. – astost Apr 25 '18 at 15:10
  • @astost You are equivocating on the phrase "no need for". There is no need because in your `class A` example, the computed property depends upon the two stored properties, which you are manipulating in the setter. The getter then gives back the "right" answer. Well, the same thing is true of AutomaticCar — it depends on a stored property, which you must manipulate if you want to get the "right" answer in _its_ getter. In other words, in class A, your getter and your setter go together, but in your AutomaticCar, your getter and your setter do _not_ go together. – matt Apr 25 '18 at 15:26
0

In your real example:

  • Vehicle currentSpeed is a stored property. That means you can assign to it directly and the property value changes.

  • AutomaticCar currentSpeed is effectively a different property — a computed property. That means that when you assign to it, all that happens is that the set function runs. No stored property values change as a result, unless you change them, right here, in the set function.

Well, in your AutomaticCar's currentSpeed set function, you didn't store the new value in the stored property, Vehicle's currentSpeed. Therefore it didn't change, because nothing happened that would change it.

As Hamish rightly says in a comment, what you meant to say is probably this:

class AutomaticCar: Car {
    override var currentSpeed: Double {
        didSet {
            self.gear = Int(self.currentSpeed/10) + 1
        }
    }
}

In that formulation, AutomaticCar currentSpeed is not a computed property; it is Vehicle currentSpeed — it is the very same stored property, along with a setter observer. So setting it sets it, storing the new value — plus now we run the setter observer and make the change in self.gear that you are after.

Note that the override of a stored property in a subclass must be one or the other, either an independent computed property or else the original stored property with the addition of a setter observer. It cannot of itself be an independent stored property.

matt
  • 515,959
  • 87
  • 875
  • 1,141