Start learning free

LESSON 561 OF 573 · OBJECT-ORIENTED PROGRAMMING - CHALLENGES

Inventory Item Class in Kotlin: Private Stock

Practice O(1) Read the full explanation

A shop keeps track of how many pieces of each item it has: the item's stock. The stock can never go below 0, and it changes only when pieces are sold or new ones arrive. So the stock is a private field, changed only through two methods that check the rules. The item's name has no rules to protect, so it stays a field any code can read.

Implement the class InventoryItem:

  • InventoryItem(name, stock) creates an item with that name and that many pieces in stock. The name is kept in a field name that other code can read.
  • sell(n) sells n pieces. If n is at least 1 and at most the stock, it lowers the stock by n and returns true. Otherwise it changes nothing and returns false: selling 0 pieces, a negative number of pieces, or more pieces than there are in stock is refused.
  • restock(n) adds n pieces to the stock when n is at least 1, and ignores n otherwise. It returns nothing.
  • getStock() returns the stock. It is the only way for other code to read it.

Keep the stock private the way the Access Modifiers lesson does in your language: self._stock in Python (private by convention), a #stock field in JavaScript, and the private keyword in Java, C++, C#, TypeScript, Kotlin, Scala and Swift. In Kotlin and Scala the constructor's second parameter is named initialStock, and the private stock starts at its value.

Each test case creates one item, then applies a list of operations to it, in order. The output has one line per test case: the item's name and a colon, then what each sell and getStock call returns, separated by spaces, with sell's answer printed as True or False. The starter code spells these names the way your language does: get_stock in Python, Sell, Restock and GetStock in C#.

 

Example 1:

Input:
    InventoryItem("Pencil", 5)
    sell(3)
    getStock()
    sell(5)
    getStock()
    restock(10)
    getStock()
Output: Pencil: True 2 False 2 12
Explanation: Selling 3 of the 5 pencils works and leaves 2. Selling 5 more is refused, because only 2 are left,
and the stock stays 2. restock(10) brings it to 12.

Example 2:

Input:
    InventoryItem("Mug", 4)
    sell(4)
    getStock()
    sell(1)
    getStock()
Output: Mug: True 0 False 0
Explanation: Selling all 4 mugs is allowed and leaves 0. With nothing left, even one mug can't be sold.

Example 3:

Input:
    InventoryItem("Lamp", 2)
    sell(0)
    sell(-3)
    restock(0)
    restock(-5)
    getStock()
    restock(1)
    sell(3)
    getStock()
Output: Lamp: False False 2 True 0
Explanation: Selling 0 or -3 lamps is refused, and restocking 0 or -5 lamps is ignored, so the stock is still 2.
After restock(1) there are 3 lamps, and selling all 3 works.

 

Constraints:

  • A name is one word of English letters. 0 <= stock <= 104 when the item is created.
  • -104 <= n <= 104 in every sell and restock.
  • A test case has from 1 to 1000 operations, and at least one of them is a sell or a getStock.
STEP 1 OF 5
    Ctrl + Enter to check

    KOTLIN · OBJECT-ORIENTED PROGRAMMING - CHALLENGES

    Inventory Item in Kotlin, explained

    Problem overview

    A shop tracks how many pieces of each item it has: the item's stock. The stock can never go below 0, and it changes only when pieces are sold or new ones arrive. So the stock is a private property, changed only through two methods that check the rules. The item's name has no rules to protect, so it stays a property any code can read.

    You write the class InventoryItem:

    • InventoryItem(name, initialStock) creates an item with that name and that many pieces.
    • sell(n) sells n pieces. If n is at least 1 and at most the stock, it lowers the stock by n and returns true. Otherwise it changes nothing and returns false.
    • restock(n) adds n pieces when n is at least 1 and ignores n otherwise. It returns nothing.
    • getStock() returns the stock, the only way for other code to read it.

    For a pencil item with 5 in stock, sell(3) works and leaves 2. Selling 5 more is refused because only 2 are left, and restock(10) brings the stock to 12.

    Approach: validate first, then change

    Both methods follow the same pattern: check whether the request is valid, and only then change the state. A refused sale must leave the stock exactly as it was, so the check has to come before the subtraction. Doing it in this order means the stock can never go negative, whatever the caller passes in. That promise is possible only because the stock is private. If it were public, any code could write a negative number into it and bypass the checks.

    Each method does a couple of comparisons and one addition or subtraction, so each runs in constant time.

    Step by step

    1. The stock property. The header already has val name, a public read-only property, and a plain parameter initialStock. In the body, declare private var stock: Int = initialStock. It is a var because sell and restock change it, and private so that only they can.
    2. Refuse bad sales. In sell, an if joins two conditions with ||: n < 1 (zero or negative pieces make no sale) or n > stock (the shop can't sell what it doesn't have). Its body returns false and changes nothing. Note that n equal to the stock is allowed: the shop may sell everything it has.
    3. Do the sale. After the if, only valid requests are left. Lower stock by n and return true.
    4. restock. An if for n >= 1 adds n to the stock. Zero or a negative number isn't a delivery, so it is ignored, and there is no else.
    5. getStock returns stock.

    The solution in Kotlin

    class InventoryItem(val name: String, initialStock: Int) {
        private var stock: Int = initialStock
    
        fun sell(n: Int): Boolean {
            if (n < 1 || n > stock) {
                return false
            }
            stock -= n
            return true
        }
    
        fun restock(n: Int) {
            if (n >= 1) {
                stock += n
            }
        }
    
        fun getStock(): Int {
            return stock
        }
    }
    

    Two Kotlin details to notice:

    • name has val in the header, so it is a public property; initialStock has none, so it is only a constructor parameter. It exists while the property initializers run, and the private stock copies it. After that, only stock is used.
    • The early return false inside the if ends the method, so the lines after it run only for valid sales. A method with no return type, like restock, returns Unit automatically.

    Using the class

    fun main() {
        val p = InventoryItem("Pencil", 5)
        println(p.name)
        println(p.sell(3))
        println(p.getStock())
        println(p.sell(5))
        println(p.getStock())
        p.restock(10)
        println(p.getStock())
        p.restock(-5)
        p.restock(0)
        println(p.getStock())
        println(p.sell(0))
        println(p.sell(-3))
        println(p.sell(12))
        println(p.getStock())
    }
    

    It prints:

    Pencil
    true
    2
    false
    2
    12
    12
    false
    false
    true
    0
    

    Kotlin prints true and false; the lesson's tests print them as True and False. The sale of 5 with 2 in stock is refused and leaves 2, restocking 0 or -5 changes nothing, and selling exactly the 12 that are there empties the shelf.

    Why return a Boolean from sell

    A sale can fail for ordinary reasons, and the caller needs to know. Printing an error inside the class would decide for every caller how failure is reported. Returning true or false leaves that choice to the code that calls sell: it may show a message, try a smaller number or ignore the result. This is a common pattern for operations that may be refused: do nothing when the request is invalid, and say so in the return value.

    restock has no such answer in this lesson. It silently ignores a bad amount, as the statement says, and returns nothing.

    Testing it

    • An item with stock 4: sell(4) returns true and leaves 0, and then sell(1) returns false.
    • An item with stock 0 at the start: every sell(1) is refused until a restock arrives.
    • Two items with stock 10 each: after sell(3) on the first, the first has 7 and the second still has 10, since each object has its own stock.
    • The limits in the constraints, -10000 and 10000, on an item with stock 7: sell(-10000) and sell(10000) both return false; restock(-10000) leaves the stock at 7, and restock(10000) makes it 10007.

    Common mistakes

    • Refusing n == stock. Writing n >= stock in the check blocks the sale of the last pieces. The test is n > stock.
    • Forgetting n < 1. A sale of -3 would raise the stock, and a sale of 0 would report success for nothing.
    • Subtracting before checking. The stock must stay untouched when the answer is false.
    • Using && instead of ||. No number is both below 1 and above the stock, so the refusal would never happen.
    • Making stock public. It would compile and pass simple tests, but outside code could set it to -4, which is exactly what the class is meant to prevent.
    • Letting restock accept negative numbers. That would act as a hidden sale with no checks.
    Keep going with Kotlin500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free