Start learning free

LESSON 561 OF 573 · OBJECT-ORIENTED PROGRAMMING - CHALLENGES

Inventory Item in Scala: Private Stock with Checks

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

    SCALA · OBJECT-ORIENTED PROGRAMMING - CHALLENGES

    Inventory Item in Scala, explained

    Problem overview

    A shop tracks how many pieces of each item it has. 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 through two methods that check the rules. The name has no rules to protect, so it stays readable by any code.

    • InventoryItem(name, initialStock) creates an item. The name is a readable field; the private stock starts at initialStock.
    • sell(n) sells n pieces if n is at least 1 and at most the stock, lowering the stock and returning true. Otherwise it changes nothing and returns false.
    • restock(n) adds n pieces when n is at least 1 and ignores it otherwise. It returns nothing.
    • getStock() returns the stock.

    With 5 pencils in stock, sell(3) works and leaves 2. Then sell(5) is refused, because only 2 are left. restock(10) brings the stock to 12.

    Approach: check first, change after

    A sale is valid only when n is between 1 and the stock, both included. So sell first rejects what is invalid: n below 1 (zero or negative) or n above the stock. Only a request that passes the check gets to change the stock, so a refused sale leaves it untouched and the stock never goes below 0. Selling exactly the whole stock is allowed.

    Step by step

    1. Declare the private field. The header has val name, which any code can read, and a plain parameter initialStock. Below the header, private var stock: Int = initialStock creates the field. It is a var because the methods change it.
    2. Refuse invalid sales. In sell, an if with n < 1 || n > stock returns false. The || means "or".
    3. Complete a valid sale. After the if, subtract n from stock and return true.
    4. restock adds n to stock only when n >= 1. Zero or a negative number isn't a delivery.
    5. getStock returns stock.

    The solution in Scala

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

    Scala details:

    • Constructor parameters and fields. val name in the header creates a public read-only field. initialStock has no val, so it is only a constructor parameter, not a field; its value is copied into the private stock.
    • private is checked by the compiler. Outside the class, item.stock is rejected: "private variable stock can only be accessed from class InventoryItem."
    • An early return ends the method at once, so the lines after the if run only for a valid sale.
    • Unit is the result type of restock, which returns nothing useful.

    Using the class

    val p = new 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())

    It prints:

    Pencil
    true
    2
    false
    2
    12

    The tests print the booleans as True and False; Scala itself prints true and false.

    The invalid requests all leave the stock alone. For an item l created with 2 lamps, l.sell(0) and l.sell(-3) both return false, and l.restock(0) and l.restock(-5) do nothing, so l.getStock() is still 2. After l.restock(1), l.sell(3) returns true and the stock is 0.

    Public name, private stock

    The two fields are treated differently on purpose. The name has no rule to protect, so val name in the header is a public, read-only field, and any code can write item.name. The stock has a rule (never below 0, changed only by valid sales and deliveries), so it is private and every change goes through sell or restock.

    The return value of sell matters. A refused sale is not an error that stops the program: the method answers false and the caller decides what to do. A sale that goes through answers true. This lets the caller tell the two cases apart without reading the stock before and after.

    Selling the exact stock is a good test of the boundary. An item with 4 mugs allows sell(4), which returns true and leaves 0. After that, even sell(1) is refused, because 1 is above the stock of 0.

    Complexity

    Each method does a couple of comparisons and at most one update, so each runs in O(1) time and the object stores a name and one integer.

    Testing

    • Pencil, 5 in stock: sell(3), getStock(), sell(5), getStock(), restock(10), getStock() give true, 2, false, 2 and 12.
    • Lamp, 2 in stock: sell(0), sell(-3), restock(0), restock(-5), getStock(), restock(1), sell(3), getStock() give false, false, 2, true and 0.

    The lamp case covers all four ways to be refused or ignored: selling 0, selling a negative number, restocking 0 and restocking a negative number.

    Common mistakes

    • Using n >= stock as the refusal test. Selling the whole stock is allowed, so only n > stock is refused.
    • Forgetting n < 1. A negative sale would raise the stock, and sell(0) would return true when it should be refused.
    • Changing the stock before checking. The check must come first, or a refused sale would still change it.
    • Accepting negative restocks. restock(-5) would lower the stock behind the back of sell's rules.
    Keep going with Scala500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free