Oli Plunkett
Oli Plunkett

Reputation: 87

Setting requirements for class variables in Swift

I am new to swift. In a group of classes / subclasses, I would like a variable in the super class to be within a required range. For example, in the following code.

class Vehicle {
    var speed: Int
    var heading: Int

    init(speed: Int, heading: Int) {
        self.speed = speed
        self.heading = heading
    }

    func turnRight() {
        if 360 - heading < 90 {
            heading = heading - 270
        } else {
            heading = heading + 90
        }
    }
}

class Car : Vehicle {
    init(speed: Int, heading: Int) {
        super.init(speed: speed, heading: heading)
    }

    override func turnRight() {
        speed = speed / 2
        if 360 - heading < 90 {
            heading = heading - 270
        } else {
            heading = heading + 90
        }
    }
}

What I don't like about the above, is that if I'm creating more subclasses for car, I'll always be forced to check that heading is within 0 and 360. I know about getters and setters, but is there a way to use a setter and still support incrementing the variable?

Ideally, I want my turnRight functions to look like:

func turnRight() {
    heading = heading + 90
}

override func turnRight() {
    speed = speed / 2
    heading = heading + 90
}

...and for my variable set in the superclass to ensure that the heading is within 0 and 360.

Upvotes: 2

Views: 459

Answers (3)

Jakub Průša
Jakub Průša

Reputation: 2405

what about move heading logic into separate structure?

Demo code is shown above.

struct Heading {

    private var heading = 0
    init(initialHeading: Int) {
        heading = initialHeading
    }
    mutating func turnRight(){
        if 360 - heading < 90 {
            heading = heading - 270
        } else {
            heading = heading + 90
        }
    }
}

class Vehicle {
    var speed: Int
    var heading: Heading

    init(speed: Int, heading: Int) {
        self.speed = speed
        self.heading = Heading(initialHeading: heading)
    }

    func turnRight() {
        heading.turnRight()
    }
}

class Car : Vehicle {
    override init(speed: Int, heading: Int) {
        super.init(speed: speed, heading: heading)
    }

    override func turnRight() {
        speed = speed / 2
        super.turnRight()
    }
}

EDIT: Update new solution with typealias and generic function turn by angle and enum values

typealias Angle = Int

enum Direction: Angle {
    case left = -90
    case right = 90 }

struct Heading {

    private var heading : Angle
    init(initialHeading: Angle) {
        heading = initialHeading
    }

    mutating func turnBy(angle: Angle){
        if 360 - heading < angle {
            heading = heading - (360 - angle)
        } else {
            heading = heading + angle
        }
    } 
}

class Vehicle {
    var speed: Int
    var heading: Heading

    init(speed: Int, heading: Int) {
        self.speed = speed
        self.heading = Heading(initialHeading: heading)
    }

    func turnRight() {
        heading.turnBy(angle: Direction.right.rawValue)
    } 
}

class Car : Vehicle {
    override init(speed: Int, heading: Int) {
        super.init(speed: speed, heading: heading)
    }

    override func turnRight() {
        super.turnRight()
        speed = speed / 2
    } 
}

Upvotes: 1

Ashley Mills
Ashley Mills

Reputation: 53161

Consider using didSet on heading

class Vehicle {
    var speed: Int
    var heading: Int {
        didSet { 
            if heading > 360 {
                heading -= 360
            } else if heading < 0{
                heading += 360
            }
        }
    }

    init(speed: Int, heading: Int) {
        self.speed = speed
        self.heading = heading
    }

    func turnRight() {
        heading += 90
    }
}

class Car : Vehicle {
    init(speed: Int, heading: Int) {
        super.init(speed: speed, heading: heading)
    }

    override func turnRight() {
        speed = speed / 2
        super.turnRight()
    }
}

Upvotes: 1

Sulthan
Sulthan

Reputation: 130122

While the implementation in Vehicle could be simpler, instead of repeating the implementation you can simply call the original implementation:

override func turnRight() {
    speed = speed / 2
    super.turnRight()
}

For a simpler implementation, we can, for example:

var heading: Int {
    didSet {
        if heading < 0 {
            heading = heading % 360 + 360
        } else {
            heading = heading % 360
        }
    }
}

Then turning can be done just using self.heading += 90.

Upvotes: 1

Related Questions