Start learning free

LESSON 253 OF 574 · FUNCTIONS & CLASSES

Rectangle Class in Swift: Properties, init and Methods

Practice O(1) Read the full explanation

A class bundles some values with the questions you can ask about them. Write a class Rectangle that remembers a rectangle's width and height, and can tell its area, its perimeter, and whether it is a square.

Implement the class Rectangle:

  • Rectangle(width, height) creates a rectangle with the given sizes.
  • area() returns the area of the rectangle: its width times its height.
  • perimeter() returns the perimeter: the length all the way around, twice the width plus twice the height.
  • isSquare() returns true if the width and the height are equal, and false otherwise.

Each line of the input is one rectangle: its width and its height. The test code first creates a Rectangle for every line, then asks each of them, in order, for its area, its perimeter and whether it is a square, and prints the three answers on one line, the boolean as True or False. So each object must keep its own sizes. The starter code spells these names the way your language does (in Go and Rust, Rectangle is a struct with methods).

 

Example 1:

Input:
    Rectangle(3, 4)
Output: 12 14 False
Explanation: The area is 3 · 4 = 12. Going around, the sides are 3 + 4 + 3 + 4 = 14.
The width and the height differ, so it isn't a square.

Example 2:

Input:
    Rectangle(5, 5)
Output: 25 20 True
Explanation: 5 · 5 = 25, and 4 sides of 5 make 20. Both sizes are 5: a square is a rectangle with equal sides.

Example 3:

Input:
    Rectangle(2, 10)
    Rectangle(10, 2)
Output:
20 24 False
20 24 False
Explanation: Two objects, each with its own sizes. Turning a rectangle on its side changes neither its area nor its perimeter.

 

Constraints:

  • 1 <= width, height <= 104
  • At most 10 rectangles per test.

Note:

Each method needs only the two sizes, so each one runs in O(1) time.

STEP 1 OF 5
    Ctrl + Enter to check

    SWIFT · FUNCTIONS & CLASSES

    Rectangle Class in Swift, explained

    Problem overview

    A class bundles values with the questions you can ask about them. Here the class is Rectangle: it remembers a width and a height, and it can answer three questions: its area(), its perimeter() and whether it isSquare().

    For a rectangle 3 wide and 4 high, the area is 3 · 4 = 12, the perimeter is 3 + 4 + 3 + 4 = 14, and it is not a square. For 5 by 5 the area is 25, the perimeter is 20, and it is a square. The lesson's tests print the square answer as True or False; Swift's own spelling of a Bool is true and false.

    Approach

    Each rectangle object must keep its own two sizes, so they live in properties: variables that belong to one object. A method then reads them without needing any argument, because inside a method width and height mean "the properties of the object this method was called on".

    Every method is one expression on two numbers, so each one runs in O(1) time.

    Step by step

    1. Declare the properties. var width: Int and var height: Int, one per line, at the top of the class. Every Rectangle gets its own pair.
    2. Store the parameters in init. The parameters are named like the properties, so self.width = width means "the property gets the parameter". Without self., plain width is the parameter.
    3. area returns width * height.
    4. perimeter returns 2 * (width + height): walking around the rectangle you pass each side once, which is twice the sum of the two different sides.
    5. isSquare returns width == height. A comparison already produces a Bool, so no if is needed.

    The solution in Swift

    class Rectangle {
        var width: Int
        var height: Int
    
        init(width: Int, height: Int) {
            self.width = width
            self.height = height
        }
    
        func area() -> Int {
            return width * height
        }
    
        func perimeter() -> Int {
            return 2 * (width + height)
        }
    
        func isSquare() -> Bool {
            return width == height
        }
    }
    

    Using it looks like this. Note the argument labels: the initializer is declared as init(width: Int, height: Int), so a call writes width: and height:.

    let a = Rectangle(width: 3, height: 4)
    print(a.area(), a.perimeter(), a.isSquare())
    let b = Rectangle(width: 5, height: 5)
    print(b.area(), b.perimeter(), b.isSquare())
    let c = Rectangle(width: 2, height: 10)
    let d = Rectangle(width: 10, height: 2)
    print(c.area(), c.perimeter(), c.isSquare())
    print(d.area(), d.perimeter(), d.isSquare())
    
    12 14 false
    25 20 true
    20 24 false
    20 24 false
    

    The last two lines show that each object keeps its own sizes, and that turning a rectangle on its side changes neither its area nor its perimeter.

    Swift details worth knowing

    • Properties need a value before init ends. Swift refuses to build an object that has an unset Int property, which is why both assignments belong in init.
    • A class is a reference type. let e = Rectangle(width: 1, height: 1) makes the name e constant, not the object's properties, so e.width = 6 is allowed and e.area() then returns 6. With a struct the same line would be an error.
    • func methods have a return type after ->. area() and perimeter() return Int, isSquare() returns Bool.

    Class or struct?

    Swift would let you write the same type as a struct, and many Swift types are structs. The difference shows when you copy. A struct is a value type: assigning it copies it. A class is a reference type: assigning it gives a second name for the same object. After let b = a and b.width = 10, with a a 2 by 3 rectangle, a struct leaves a.area() at 6 while b.area() is 30. With the class, a.area() and b.area() are both 30, because there is only one object. This lesson asks for a class, so that is the behaviour to expect.

    Trying it on your own

    Besides the examples above, a few small rectangles are worth checking by hand against the code: a 1 by 1 rectangle (area 1, perimeter 4, a square), a 1 by 10000 rectangle (area 10000, perimeter 20002, not a square) and a pair of objects with the same sizes, which must give the same answers without affecting each other.

    Edge cases and common mistakes

    • Missing parentheses in the perimeter. 2 * width + height multiplies only the width: for 2 by 10 it gives 14 instead of 24.
    • Writing width = width in init. Both sides are the parameter, so the property is never set. Use self.width = width.
    • Sharing sizes between objects. Keep the sizes in properties of the object, not in values outside the class, so two rectangles never overwrite each other.
    • Using if for isSquare. if width == height { return true } else { return false } works but only repeats what return width == height says.
    • Forgetting the labels when creating the object: Rectangle(3, 4) doesn't compile for this initializer.

    Testing

    The lesson's tests create several rectangles first and then ask each one its three questions, so a bug that shares data between objects shows up quickly. Try these in a file of your own:

    • Rectangle(width: 3, height: 4) gives area 12, perimeter 14, not a square.
    • Rectangle(width: 5, height: 5) gives area 25, perimeter 20, a square.
    • Rectangle(width: 2, height: 10) and Rectangle(width: 10, height: 2) both give area 20 and perimeter 24.

    Check each answer with pencil and paper before you run the code. If the numbers disagree, the most likely cause is a missing pair of parentheses in perimeter or a property that was never assigned in init.

    Key takeaways

    • Properties hold the data of one object; methods answer questions about it.
    • self.width = width separates the property from the parameter of the same name.
    • A comparison like width == height is already a Bool.
    • A class is a reference type: two names can point to the same object.
    Keep going with Swift500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free