Final understanding of runtime polymorphism via overriding.
Shape
+draw()
Circle
+draw()
Rectangle
+draw()
Circle ▷ ShapeRectangle ▷ Shape
Key Takeaways
✓ Runtime polymorphism allows method calls to invoke the correct subclass implementation dynamically.
This dynamic dispatch is not obvious from reading code alone but is clear when watching method calls resolve at runtime.
✓ Overriding replaces base class methods in subclasses, enabling flexible behavior customization.
Seeing the overridden methods highlighted helps understand how subclasses change behavior.
✓ The base class method is called only if no subclass override exists, showing fallback behavior.
This clarifies that polymorphism does not always mean subclass methods are called; base methods remain accessible.
Practice
(1/5)
1. When a class inherits from multiple classes that have a method with the same name, describe the step-by-step process the Method Resolution Order (MRO) uses to determine which method is called.
easy
A. MRO uses a linearization algorithm that merges the order of parents and their ancestors to find the method.
B. MRO searches the first parent class fully before moving to the next parent class.
C. MRO always calls the method from the last parent class listed in the inheritance.
D. MRO randomly picks the method from any parent class that defines it.
Solution
Step 1: Understand naive search
MRO does not simply search the first parent class fully before moving to the next; it uses a more sophisticated approach.
Step 2: Recognize MRO linearization
MRO uses a specific linearization (like C3 linearization) that merges parent classes and their ancestors in a consistent order.
Step 3: Eliminate incorrect options
MRO always calls the method from the last parent class listed in the inheritance is incorrect because the last parent is not always chosen; order and ancestors matter. MRO randomly picks the method from any parent class that defines it is incorrect because MRO is deterministic, not random.
Final Answer:
Option A -> Option A
Quick Check:
MRO merges inheritance hierarchies to find the correct method in a predictable order.
Hint: MRO = deterministic linearization of inheritance graph
Common Mistakes:
Assuming simple left-to-right search suffices
Believing last parent always overrides
Thinking method choice is random
2. Considering extensibility in the Snake and Ladder game design, what is a key trade-off when embedding snakes and ladders directly as attributes inside the Board class versus modeling them as separate entities?
medium
A. Modeling snakes and ladders as separate entities increases runtime complexity significantly
B. Embedding snakes and ladders inside Board simplifies design but reduces flexibility to add new types of board elements later
C. Embedding snakes and ladders inside Board improves encapsulation and makes the Board immutable
D. Modeling snakes and ladders separately forces duplication of position data, increasing memory usage unnecessarily
Solution
Step 1: Embedding snakes/ladders inside Board
This approach simplifies initial design but tightly couples Board to these elements.
Step 2: Impact on extensibility
Tightly coupled design makes it harder to add new board elements (e.g., portals, traps) without modifying Board.
Step 3: Modeling as separate entities
Allows easy extension by adding new element types without changing Board internals.
Step 4: Complexity and memory considerations
Separate entities add minimal overhead; runtime complexity impact is negligible.
Final Answer:
Option B -> Option B
Quick Check:
Trade-off is between simplicity and extensibility, not runtime complexity or memory bloat.
Hint: Tight coupling simplifies now but blocks future extensions [OK]
Common Mistakes:
Thinking separate entities cause big runtime overhead
Believing embedding improves encapsulation and immutability
Assuming separate entities cause memory bloat
3. Consider the following buggy code snippet from a thread-safe observer pattern implementation. Which line contains the subtle bug that can cause unsubscribed observers to still receive notifications?
def unsubscribe(self, observer, event_type):
with self.lock:
if event_type in self.observers:
self.observers[event_type].remove(observer)
if not self.observers[event_type]:
del self.observers[event_type]
Assume that observer may not be subscribed to event_type when unsubscribe is called.
medium
A. Line 5: No handling of empty observer dictionary
B. Line 2: Lock is not acquired properly
C. Line 3: Missing check if observer is in the set before remove()
D. Line 4: Deleting event_type key prematurely
Solution
Step 1: Analyze unsubscribe logic
Line 3 calls remove() on the set without checking if observer exists, which raises KeyError if observer not subscribed.
Step 2: Identify fix
Check if observer in self.observers[event_type] before remove() to avoid errors and ensure proper removal.
Final Answer:
Option C -> Option C
Quick Check:
remove() without membership check causes runtime error [OK]
Hint: remove() without membership check can raise error [OK]
Common Mistakes:
Assuming remove() silently ignores missing elements
4. Suppose you want to extend the Command Pattern to support commands that can be executed multiple times (reused) and also support undo/redo correctly. Which modification to the invoker's undo/redo management is necessary to handle this scenario without corrupting state?
hard
A. Store only one instance of each command and reuse it for all executions, pushing it multiple times onto undo stack.
B. Clear both undo and redo stacks after every command execution to avoid reuse issues.
C. Create a new command instance for each execution and push that instance onto the undo stack, ensuring undo/redo operate on the correct state snapshot.
D. Avoid using undo/redo stacks and instead recompute state from scratch on each undo or redo.
Solution
Step 1: Understand reuse implications
Reusing the same command instance for multiple executions causes undo/redo to affect the wrong state because the command's internal state may change.
Step 2: Identify correct approach
Creating a new command instance per execution ensures each undo/redo corresponds to the exact executed command instance and its parameters.
Step 3: Confirm undo/redo stack integrity
This approach preserves correct ordering and state consistency during undo/redo operations.
Final Answer:
Option C -> Option C
Quick Check:
New instances per execution prevent state corruption on undo/redo [OK]
Hint: Each execution needs a fresh command instance for correct undo/redo [OK]
Common Mistakes:
Reusing command instances causing incorrect undos
Clearing stacks unnecessarily losing history
5. If the Library Management System must support reserving books that are currently loaned out, which design change best handles the edge case where multiple users reserve the same book simultaneously?
hard
A. Let the User class maintain their own reservation list independently without central coordination.
B. Allow multiple reservations by updating the book's status to 'reserved' without tracking order.
C. Add a reservation queue in the LoanManager and process reservations in FIFO order with atomic updates.
D. Implement a polling mechanism where users repeatedly check book availability without reservations.
Solution
Step 1: Why a reservation queue?
FIFO queue ensures fairness and order in handling multiple reservations.
Step 2: Why not multiple reservations without order?
Allow multiple reservations by updating the book's status to 'reserved' without tracking order. causes ambiguity and race conditions in fulfilling reservations.
Step 3: Why not user-maintained reservations?
Let the User class maintain their own reservation list independently without central coordination. lacks centralized control, risking inconsistent reservation states.
Step 4: Why not polling without reservations?
Implement a polling mechanism where users repeatedly check book availability without reservations. leads to poor user experience and race conditions.
Final Answer:
Option C -> Option C
Quick Check:
Centralized, ordered reservation management with atomic updates handles concurrency and fairness.
Hint: Use a centralized FIFO reservation queue to handle concurrent reservations fairly [OK]
Common Mistakes:
Ignoring reservation order and fairness
Decentralizing reservation tracking
Relying on user polling instead of system-managed reservations
Recommended
Ready to prove it?
Pass the test and this pattern moves unknownstrongwhile earning +1 Grip toward your certificate.