Start learning free

LESSON 560 OF 573 · OBJECT-ORIENTED PROGRAMMING - CHALLENGES

Thermostat Class in Kotlin: Private Properties

Practice O(1) Read the full explanation

A thermostat keeps a target temperature, and the target must always stay between 10 and 30 degrees. If any code could change the target directly, nothing would stop it from setting 95. So the target is a private field: only the thermostat's own methods can change it, and every one of them keeps it between 10 and 30.

Implement the class Thermostat:

  • Thermostat() creates a thermostat whose target is 20.
  • setTarget(t) sets the target to t. A value below 10 sets it to 10, and a value above 30 sets it to 30.
  • warmer() raises the target by 1 and cooler() lowers it by 1, but neither ever takes it outside 10 to 30: at 30, warmer() leaves it at 30, and at 10, cooler() leaves it at 10.
  • getTarget() returns the target. It is the only way for other code to read it.

Keep the target private the way the Access Modifiers lesson does in your language: self._target in Python (private by convention), a #target field in JavaScript, and the private keyword in Java, C++, C#, TypeScript, Kotlin, Scala and Swift.

The input is a list of operations, applied in order to one new Thermostat. The output lists what the getTarget calls return, in order. The starter code spells these names the way your language does: set_target and get_target in Python, SetTarget, Warmer, Cooler and GetTarget in C#.

 

Example 1:

Input:
    getTarget()
    warmer()
    warmer()
    getTarget()
    cooler()
    getTarget()
Output: 20 22 21
Explanation: A new thermostat starts at 20. Two warmer() calls take it to 22, and cooler() brings it back to 21.

Example 2:

Input:
    setTarget(35)
    getTarget()
    warmer()
    getTarget()
    cooler()
    getTarget()
Output: 30 30 29
Explanation: 35 is above 30, so the target becomes 30. warmer() can't go past 30, so the target stays 30.
cooler() lowers it to 29.

Example 3:

Input:
    setTarget(4)
    getTarget()
    cooler()
    getTarget()
    setTarget(10)
    warmer()
    getTarget()
Output: 10 10 11
Explanation: 4 is below 10, so the target becomes 10, and cooler() can't go below 10. setTarget(10) keeps 10,
since 10 itself is allowed, and warmer() raises it to 11.

 

Constraints:

  • -1000 <= t <= 1000
  • A test case has from 1 to 1000 operations, and at least one of them is getTarget.
STEP 1 OF 7
    Ctrl + Enter to check

    KOTLIN · OBJECT-ORIENTED PROGRAMMING - CHALLENGES

    Thermostat in Kotlin, explained

    Problem overview

    A thermostat keeps a target temperature, and the target must always stay between 10 and 30 degrees. If any code could assign the target directly, nothing would stop it from setting 95. So the target is a private property: only the thermostat's own methods can change it, and each of them keeps it in range.

    You write the class Thermostat:

    • A new thermostat has a target of 20.
    • setTarget(t) sets the target to t. A value below 10 becomes 10 and a value above 30 becomes 30.
    • warmer() raises the target by 1 and cooler() lowers it by 1, never leaving the range 10 to 30.
    • getTarget() returns the target. It is the only way for other code to read it.

    After setTarget(35) the target is 30. A further warmer() leaves it at 30, and cooler() brings it to 29.

    Approach: one place that enforces the rule

    The rule "between 10 and 30" could be checked in three places: in setTarget, in warmer and in cooler. Repeating it three times invites mistakes, and if the limits ever change you must find all three. Better to write the rule once, in setTarget, and let the other two methods go through it. warmer calls setTarget(target + 1). At 30 that asks for 31, and setTarget turns it back into 30. cooler works the same way at the bottom: at 10, the request for 9 becomes 10.

    This is the point of making the property private: the class controls every way of changing it, so the rule only has to be correct in the class.

    Step by step

    1. The property. At the top of the class, declare private var target: Int = 20. It is a var because the methods change it, and private so that only they can. Every new thermostat starts at 20.
    2. Too low. In setTarget, an if for t < 10 sets target to 10. A value that is too low isn't refused; it becomes the lowest allowed target.
    3. Too high. An else if for t > 30 sets target to 30.
    4. Everything else. The else sets target to t. The values 10 and 30 themselves are allowed, so they end up here and are kept as they are.
    5. warmer and cooler call setTarget with target + 1 and target - 1.
    6. getTarget returns target.

    The solution in Kotlin

    class Thermostat {
        private var target: Int = 20
    
        fun setTarget(t: Int) {
            if (t < 10) {
                target = 10
            } else if (t > 30) {
                target = 30
            } else {
                target = t
            }
        }
    
        fun warmer() {
            setTarget(target + 1)
        }
    
        fun cooler() {
            setTarget(target - 1)
        }
    
        fun getTarget(): Int {
            return target
        }
    }
    

    Inside the class, target is visible to every method. Outside it is not. Code like this does not compile:

    fun main() {
        val t = Thermostat()
        t.target = 95
    }
    

    The compiler reports that it cannot access the variable target because it is private in Thermostat. The only ways in are the public methods, so the target can never leave the range. (Kotlin also lets you write properties with custom getters and setters, but this lesson uses explicit methods.)

    Using the class

    fun main() {
        val th = Thermostat()
        println(th.getTarget())
        th.setTarget(35)
        println(th.getTarget())
        th.warmer()
        println(th.getTarget())
        th.cooler()
        println(th.getTarget())
        th.setTarget(4)
        println(th.getTarget())
        th.cooler()
        println(th.getTarget())
        th.setTarget(10)
        th.warmer()
        println(th.getTarget())
    }
    

    It prints:

    20
    30
    30
    29
    10
    10
    11
    

    Read it from the top: a new thermostat is at 20; 35 is clamped to 30; warmer() can't go past 30; cooler() gives 29; 4 is clamped to 10 and cooler() can't go lower; finally 10 is allowed as it is, and warmer() raises it to 11.

    Why a private property can share its name with a getter

    The property is called target and the method getTarget(). In Kotlin a public property target would get a generated getter with the same JVM name as your method, and the compiler would complain about a clash. A private property gets no generated getter, so the explicit getTarget() is fine. That is one more benefit of keeping the property private: the class owns its storage, and the methods are its whole public surface.

    Testing it

    Good inputs are the ones that touch the boundaries:

    • Thirty-one calls to warmer() on a new thermostat: getTarget() then returns 30. Ten calls already give 30, so the extra ones change nothing.
    • setTarget(30) then warmer(): the target is 30.
    • setTarget(10) then cooler(): the target is 10.
    • setTarget(-1000) and setTarget(1000), the extremes the constraints allow: 10 and 30.

    Common mistakes

    • Getting the limits off by one. A condition like t < 11 or t > 29 would wrongly squash the allowed values 10 and 30. Test the boundary values themselves.
    • Refusing out-of-range values. The rule is to clamp them to the nearest limit, not to ignore the call.
    • Writing target++ in warmer. It skips the range check, so the target could reach 31. Go through setTarget.
    • Making the property public. The code would still compile and pass simple tests, but any caller could set 95. The private keyword is what makes the rule binding.
    • Giving the property and the method the same name. Here the property is target and the method is getTarget(), so they stay distinct.
    Keep going with Kotlin500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free