Problem overview
A company pays every employee a salary. A manager is an employee too, but earns a bonus on top of the salary. The task is to write two classes so that a manager reuses everything an employee has and changes only how its pay is worked out.
Employee has:
- an initializer
Employee(name, salary); the name and the salary are private toEmployee; pay(), which returns the salary;describe(), which returns the text<name> earns <pay>, such asAna earns 3000.
Manager inherits from Employee. It has an initializer Manager(name, salary, bonus) that stores the bonus itself and lets the parent store the name and the salary, and it overrides pay() to return the parent's pay() plus the bonus. It does not write describe() again.
For Ana, an employee with salary 3000, describe() gives Ana earns 3000. For Bob, a manager with salary 4000 and bonus 1000, it gives Bob earns 5000.
Approach
The key idea is that describe() calls pay() instead of reading the salary. When describe() runs on a plain employee, pay() is the employee's version. When it runs on a manager, Swift calls the manager's overriding version, because a method call looks at the real type of the object. So the same describe() code shows the bonus for managers without being copied.
The salary is private to Employee, so Manager can't read it. It gets the salary the proper way: by asking the parent's pay() through super. The parent decides how an employee is paid, and the manager adds its bonus on top.
Step by step
- Declare
private let name: StringinEmployee. Private means only code insideEmployeeuses it, not evenManager. - Declare
private let salary: Intthe same way. - Store both in
init:self.name = nameandself.salary = salary. Plainnameis the parameter,self.namethe property. pay()returnssalary.describe()returns"\(name) earns \(pay())". The\( )puts a value into a string, a number too. It callspay(), not thesalaryproperty.- Declare
Manager: Employee. The: Employeegives it the name, the salary,payanddescribe. Add its ownprivate let bonus: Int. - In Manager's
init, store the bonus first:self.bonus = bonus. Swift requires a class to set its own properties before calling the parent's initializer. - Then call
super.init(name, salary). It runsEmployee's initializer, the only code that can set the private name and salary. - Override
pay(): mark itoverride func pay() -> Intand returnsuper.pay() + bonus.
The solution in Swift
class Employee {
private let name: String
private let salary: Int
init(_ name: String, _ salary: Int) {
self.name = name
self.salary = salary
}
func pay() -> Int {
return salary
}
func describe() -> String {
return "\(name) earns \(pay())"
}
}
class Manager: Employee {
private let bonus: Int
init(_ name: String, _ salary: Int, _ bonus: Int) {
self.bonus = bonus
super.init(name, salary)
}
override func pay() -> Int {
return super.pay() + bonus
}
}
Using both classes together in one array:
let people: [Employee] = [Employee("Ana", 3000), Manager("Bob", 4000, 1000), Manager("Cleo", 5000, 0), Employee("Dan", 5000), Manager("Eve", 7000, 2500)]
for p in people { print(p.describe()) }
print(people[1].pay())
Ana earns 3000
Bob earns 5000
Cleo earns 5000
Dan earns 5000
Eve earns 9500
5000
The array has the type [Employee], yet each manager in it still uses its own pay(). Cleo, whose bonus is 0, earns exactly the salary, like Dan.
Swift details worth knowing
overrideis mandatory. Redefining a parent's method without it fails:overriding declaration requires an 'override' keyword. The keyword protects you from overriding something by accident.- Initializer order. Calling
super.init(name, salary)before settingbonusfails withproperty 'self.bonus' not initialized at super.init call. In the other order, a subclass first initializes its own properties, then calls up. - Private is respected by subclasses. Writing
salary + bonusinsideManagerfails with'salary' is inaccessible due to 'private' protection level. That is why the manager callssuper.pay(). super.pay()versuspay(). Inside the override,pay()alone means "this same method", so it would call itself forever. The program crashes instead of returning a number.- A subclass gets
describe()for free. Nothing inManagermentions it, yetManager("Bob", 4000, 1000).describe()works.
Edge cases and common mistakes
- Copying
describe()intoManager. It would work now but forces two copies to stay in sync. - Describing with
salaryinstead ofpay(). Then managers would show only their salary: Bob would earn 4000. - A zero bonus. It must not change the pay.
- Equal names. Two people may have the same name, and each object keeps its own values.
Reading the call chain
Follow Manager("Bob", 4000, 1000).describe() once. The manager has no describe() of its own, so Swift runs the one inherited from Employee. That code calls pay(), and since the object is a Manager, the override runs. The override calls super.pay(), which is Employee's version and returns the salary, 4000. Adding the bonus gives 5000, and the string becomes Bob earns 5000.
Why not store the salary in Manager too?
A second copy of the salary in Manager would work for the tests, but it is a design smell. The manager would then hold the same fact in two places, and a change to how employees are paid would need to be repeated. By asking super.pay(), the manager says only what makes it different: "the pay of an employee, plus a bonus". If Employee.pay() changed one day, for example to include a fixed allowance, every manager would follow automatically.
Complexity
Each call is constant time: pay() reads a field, the manager's pay() adds two numbers, and describe() builds one short string. Creating n people takes O(n) time and space in total.
Testing
- An employee Ana with 3000 and a manager Bob with 4000 and a bonus of 1000:
Ana earns 3000andBob earns 5000. - A manager Cleo with 5000 and a bonus of 0, and an employee Dan with 5000: both lines say 5000.
- A mix in any order, such as manager Eve 7000 + 2500:
Eve earns 9500.
