Start learning free

LESSON 562 OF 573 · OBJECT-ORIENTED PROGRAMMING - CHALLENGES

Employees and Managers in Kotlin: Inheritance

Practice O(1) Read the full explanation

A company pays every employee a salary. A manager is an employee too, but earns a bonus on top of the salary. Write the two classes so that a manager reuses everything an employee has, and changes only how its pay is worked out.

Implement the class Employee:

  • Employee(name, salary) creates an employee. The name and the salary are private to Employee.
  • pay() returns the salary.
  • describe() returns the text <name> earns <pay>, where the amount is what pay() returns, for example Ana earns 3000.

and the class Manager, which inherits from Employee:

  • Manager(name, salary, bonus) lets the parent's constructor store the name and the salary, and stores the bonus itself, private to Manager.
  • pay() returns the parent's pay() plus the bonus. Call the parent's version, as in the lesson Calling the Parent Method: the salary is private to Employee, and the parent's pay() is what knows how an employee is paid.
  • describe() is not written again: Manager inherits it unchanged. Because describe() calls pay(), a manager's description shows the manager's pay, bonus included.

The input is a list of people, one per line: employee name salary or manager name salary bonus. For each line, the code that tests your classes creates that object and prints what its describe() returns, on a line of its own. The starter code spells these names the way your language does.

 

Example 1:

Input:
    employee Ana 3000
    manager Bob 4000 1000
Output:
    Ana earns 3000
    Bob earns 5000
Explanation:
Ana's pay is her salary. Bob's pay is the parent's pay, his salary 4000, plus his bonus 1000.
Bob's describe() is Employee's describe(), but the pay() it calls is Manager's.

Example 2:

Input:
    manager Cleo 5000 0
    employee Dan 5000
Output:
    Cleo earns 5000
    Dan earns 5000
Explanation: A manager whose bonus is 0 earns exactly the salary, like an employee.

Example 3:

Input:
    manager Eve 7000 2500
    employee Finn 2800
    employee Gus 3100
    manager Hana 6000 500
Output:
    Eve earns 9500
    Finn earns 2800
    Gus earns 3100
    Hana earns 6500
Explanation: Employees and managers come in any order, and each object keeps its own name and numbers.

 

Constraints:

  • 0 <= salary <= 106
  • 0 <= bonus <= 106
  • A name is one word of 1 to 20 English letters. Two people may have the same name.
  • At most 100 people per test case.
STEP 1 OF 3
    Ctrl + Enter to check

    KOTLIN · OBJECT-ORIENTED PROGRAMMING - CHALLENGES

    Employees And Managers in Kotlin, explained

    Problem overview

    A company pays every employee a salary. A manager is an employee too, but earns a bonus on top. You write two classes so that a manager reuses everything an employee has and changes only how its pay is worked out.

    The class Employee has:

    • a constructor taking a name and a salary, both private to Employee;
    • pay(), which returns the salary;
    • describe(), which returns the text <name> earns <pay>, using what pay() returns.

    The class Manager inherits from Employee. It takes a name, a salary and a bonus, passes the first two to the parent and keeps the bonus privately. Its pay() returns the parent's pay plus the bonus. describe() is not written again.

    An employee Ana with salary 3000 is described as Ana earns 3000. A manager Bob with salary 4000 and bonus 1000 is described as Bob earns 5000.

    Approach: override one method, inherit the rest

    The only difference between the two kinds of people is how pay is computed. So only pay changes. Manager overrides it, and everything else (the stored name and salary, and describe) is inherited unchanged.

    The key point is that describe calls pay() instead of reading the salary directly. When describe runs on a manager, the call pay() goes to the manager's version, so the bonus shows up without a second describe. This is called polymorphism: the same call runs different code depending on the actual kind of object.

    The second point is that the salary is private to Employee, so Manager cannot read it. It does not need to: super.pay() asks the parent's version, which knows how an employee is paid, and the manager adds its bonus to that.

    Step by step

    1. Employee's header. open class Employee(private val name: String, private val salary: Int). The open keyword is needed because Kotlin classes are final by default: without it no class could inherit from Employee. The private val parameters become private properties.
    2. pay in Employee. It is marked open too, since a method also has to allow overriding. It returns salary.
    3. describe. Return a string template: "$name earns ${pay()}". The $name inserts a variable, and ${...} inserts the value of any expression, here a method call. It calls pay(), not salary.
    4. Manager's header. class Manager(name: String, salary: Int, private val bonus: Int) : Employee(name, salary). After the colon, Employee(name, salary) calls the parent's constructor. name and salary are plain parameters here (no val), because the parent stores them. Only bonus is a property.
    5. pay in Manager. Mark it override and return super.pay() + bonus.

    The solution in Kotlin

    open class Employee(private val name: String, private val salary: Int) {
        open fun pay(): Int {
            return salary
        }
    
        fun describe(): String {
            return "$name earns ${pay()}"
        }
    }
    
    class Manager(name: String, salary: Int, private val bonus: Int) : Employee(name, salary) {
        override fun pay(): Int {
            return super.pay() + bonus
        }
    }
    

    Notice what is missing from Manager: there is no describe and no stored name or salary. Notice also what is marked: open on the class and on pay in the parent, override on pay in the child. describe is not open, so nobody can override it by accident.

    Using the classes

    fun main() {
        val people = listOf(Employee("Ana", 3000), Manager("Bob", 4000, 1000), Manager("Cleo", 5000, 0))
        for (x in people) println(x.describe())
        val e: Employee = Manager("Eve", 7000, 2500)
        println(e.pay())
    }
    

    It prints:

    Ana earns 3000
    Bob earns 5000
    Cleo earns 5000
    9500
    

    The list holds both kinds, and the loop calls describe() on each. A manager with a bonus of 0, like Cleo, earns exactly the salary. The last lines show that a variable of type Employee can hold a manager, and e.pay() still runs the manager's version: 7000 plus 2500.

    What the compiler says

    Three mistakes come up often, and Kotlin catches each one at compile time.

    • Reading the private salary in Manager, as in return salary + bonus, fails: the compiler says it cannot access salary because it is private in Employee. Use super.pay().
    • Forgetting open on the parent's pay fails with: 'pay' in 'Employee' is final and cannot be overridden.
    • Calling pay() inside Manager.pay instead of super.pay() compiles, but the method calls itself forever and the program ends with a StackOverflowError.

    Common mistakes

    • Reading salary in describe. Then managers would be described with their salary only, the bonus missing.
    • Rewriting describe in Manager. It works, but it copies code the child gets for free, and the two copies can drift apart.
    • Adding val to name and salary in Manager's header. It compiles, but it declares second, public properties that store the same data again, which breaks the lesson's rule that these values are private to Employee. Plain parameters are enough.
    • Forgetting override. Kotlin requires it, so the compiler tells you when a method meant to replace the parent's does not match its signature.
    Keep going with Kotlin500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free