Week 10: OOP — Encapsulation & Abstraction
1983 words
10 min read
Visual companion
Python
Type and operator map
Python Week 1: the first filter for runtime behavior
View
Revision summary
What this note is really saying
Short form
# Week 10: OOP — Encapsulation & Abstraction > **BSCS1001 — IIT Madras BS Degree** **Prerequisite:** Week 3 (Procedures), Week 6 (Dictionaries) **Cross-links:** BSCS1002-Python (Week 11 — Classes), BSCS2002-PDSA (Week 10 — OOP Basics) ## 1. Motivation: Beyond Procedures Procedures provide **some** modularity, but th...

Week 10: OOP — Encapsulation & Abstraction
BSCS1001 — IIT Madras BS Degree Prerequisite: Week 3 (Procedures), Week 6 (Dictionaries) Cross-links: BSCS1002-Python (Week 11 — Classes), BSCS2002-PDSA (Week 10 — OOP Basics)
1. Motivation: Beyond Procedures
Procedures provide some modularity, but they have limitations:
- State is external — data lives outside the procedure
- Side effects are unpredictable — any procedure can modify any data
- No ownership — data isn't clearly associated with its operations Encapsulation solves these by packaging data AND procedures together.
Real-world analogy: A vending machine. You interact with it through a clear interface (insert money, press button, get item). You don't need to know how it works internally. The machine encapsulates its mechanism and exposes only what you need.
2. The Limitations of Procedures
Procedural Approach
pseudomarksList = [85, 72, 91, 68] // Data lives here Procedure Average(L) { // Procedure operates on data sum = 0 foreach x in L { sum = sum + x } return(sum / length(L)) } result = Average(marksList) // Called externally
Problems
| Problem | Example |
|---|---|
| No connection | Average doesn't "belong" to marksList |
| Global data | Any procedure could modify marksList |
| Repeated computation | Each call to Average re-computes |
| No data hiding | Anyone can see marksList |
Encapsulation Solution
pseudo// ClassAve encapsulates both data AND procedures ClassAve { data: marksList data: aValue (cached average) procedure average() { if (aValue == -1) { compute and store in aValue } return(aValue) } procedure addStudent(newMark) { marksList = marksList ++ [newMark] aValue = -1 // Invalidate cache } }
3. What is Encapsulation?
Encapsulation is the bundling of data and procedures that operate on that data into a single unit (called a class or object).
(Diagram)
Key Benefits
| Benefit | Description |
|---|---|
| Modularity | Self-contained units (objects) |
| Data hiding | Internal details are hidden |
| State retention | Object remembers between calls |
| Cache/invariants | Object can store derived data |
| Natural mapping | Real-world entities map to objects |
4. Class and Object
Class = Blueprint
A class defines the structure — what data fields and procedures an object will have.
Object = Instance
An object is a concrete instance of a class.
javaClassAve (class) CT (object of ClassAve) ┌──────────────────────┐ ┌──────────────────────┐ │ Fields: │ │ marksList: [85,72...]│ │ marksList │ ──► │ aValue: -1 │ │ aValue │ │ │ │ Procedures: │ │ average() → compute │ │ average() │ │ addStudent() │ │ addStudent() │ └──────────────────────┘ └──────────────────────┘
Multiple Objects from One Class
pseudoClass: ClassAve Objects: CT (for Total marks) → marksList = totals of all students MaT (for Maths) → marksList = Maths marks PhT (for Physics) → marksList = Physics marks ChT (for Chemistry) → marksList = Chemistry marks
Each object has its own copy of the data fields.
5. Private vs Public
Information Hiding
Some fields and procedures are private (internal) and some are public (accessible from outside).
sqlClassAve { // Private fields (hidden from outside) private marksList private aValue // Public procedures (interface to outside) public average() public addStudent(newMark) }
Why Hide Data?
| Reason | Explanation |
|---|---|
| Prevent corruption | External code can't directly mess with internal data |
| Maintain invariants | Object controls access to ensure consistency |
| Flexibility | Can change implementation without affecting users |
| Reduced complexity | Users only need to understand the interface |
Example: Why MarksList Should Be Private
If marksList were public:
pseudomarksList = CT.marksList // External code gets the list marksList[0] = 1000 // DIRECT modification — bypasses addStudent! aValue still = -1 // Object doesn't know data changed! CT.average() would be WRONG // Cached value is stale
By making marksList private, all changes go through
addStudent(), which properly invalidates the cache.6. The Classroom Data Example
Problem
We frequently ask: "What is the average in a subject?" Computing it each time is wasteful if the data doesn't change.
Solution: Cache the Average
sqlClassAve { private marksList private aValue // -1 means "not computed yet" public procedure average() { if (aValue == -1) { // Compute average from scratch sum = 0 foreach m in marksList { sum = sum + m } aValue = sum / length(marksList) } return(aValue) } public procedure addStudent(newMark) { marksList = marksList ++ [newMark] aValue = -1 // Invalidate cache — needs recomputation } }
How Caching Works
pseudoCT = new ClassAve() // CT.marksList = [], CT.aValue = -1 CT.addStudent(85) // marksList = [85], aValue = -1 CT.addStudent(72) // marksList = [85, 72], aValue = -1 avg = CT.average() // Computes: (85+72)/2 = 78.5, stores in aValue // Returns 78.5 avg = CT.average() // aValue != -1, returns 78.5 immediately (cached!) CT.addStudent(91) // marksList = [85, 72, 91], aValue = -1 (cache reset) avg = CT.average() // Recomputes: (85+72+91)/3 = 82.67
Comparison with Procedures
| Aspect | Procedural | Encapsulated (OOP) |
|---|---|---|
| Call | AveTotal = Avemarks(Total) | AveTotal = CT.average() |
| Cache | Not possible (no state) | ✅ Yes — stores result |
| Data | Passed as parameter | Stored internally |
| Side effects | Modify external data | Controlled via interface |
7. Abstraction
Abstraction means exposing only essential features while hiding implementation details.
The Principle: Separate "What" from "How"
javascript// What it does (interface): CT.average() // → Returns the average of the stored marks // How it does it (implementation): // 1. Check if aValue == -1 // 2. If yes, compute sum / count, store in aValue // 3. Return aValue
The caller only needs to know what it does, not how.
Levels of Abstraction
(Diagram)
8. Derived Types
The Problem
Some procedures make sense only for certain categories:
number()works for shirts (count by units) but not for grapes (sold by weight)quantity()works for grapes (weight) but not for shirts
Solution: Derived Types
Create a base type with common procedures, then derive specific types with additional procedures.
pseudoCategory (base) ├── NumberCategory (adds: number()) └── QuantityCategory (adds: quantity())
javascript// Base type Category { count() min() max() average() } // Derived type: NumberCategory extends Category { number() // Specific to countable items } // Derived type: QuantityCategory extends Category { quantity() // Specific to measurable items }
9. Encapsulation vs Procedural Approach
| Aspect | Procedural | Encapsulation (OOP) |
|---|---|---|
| Data location | External, passed as parameters | Internal to object |
| State | No retained state between calls | Object retains state |
| Caching | Not possible | ✅ Cache computed values |
| Data hiding | Not possible | ✅ Private fields |
| Side effects | Unpredictable | ✅ Controlled via interface |
| Real-world mapping | Weaker | ✅ Stronger |
| Complexity | Simpler for small programs | Better for large programs |
| Reusability | Via procedures | Via classes (blueprints) |
10. Practice Questions
Basic Questions
Q1. What is encapsulation?
Show AnswerEncapsulation is bundling data and the procedures that operate on that data into a single unit (class/object). It also involves hiding internal details from the outside world. Q2. What is the difference between a class and an object? Show AnswerA class is a blueprint/template that defines the structure (fields and procedures). An object is a concrete instance created from that blueprint, with its own copy of the data fields. Q3. What is a private field? Why would you make a field private? Show AnswerA private field can only be accessed from within the object itself, not from outside. We make fields private to prevent external code from directly modifying internal data, which could break invariants or bypass important logic. Q4. In theClassAveexample, why isaValueset to -1 afteraddStudent? Show AnsweraValuecaches the computed average. When a new student is added, the cached average is no longer accurate. SettingaValue = -1(a sentinel value meaning "not computed") forcesaverage()to recompute the value next time it's called.
Intermediate Questions
Q5. Explain how encapsulation enables caching in the
ClassAve example.Show AnswerIn the procedural approach, each call toAverage()must recompute the sum because there's nowhere to store the result. In the OOP approach, the object retains state between calls. TheaValuefield stores the computed average. On subsequent calls,average()checksaValuefirst — if it's not -1, it returns the cached value instantly. This makes repeated calls much faster. Q6. What is the difference between encapsulation and abstraction? Show Answer
- Encapsulation is the mechanism — bundling data + procedures, hiding internal details.
- Abstraction is the principle — exposing only what's necessary, focusing on "what" not "how".
Encapsulation enables abstraction. The private fields are the encapsulation; the public interface is the abstraction. Q7. Design a classBankAccountwith appropriate fields and procedures. Show AnswerjavaClass BankAccount { private balance // Current balance private accountNumber // Unique identifier public deposit(amount) { balance = balance + amount } public withdraw(amount) { if (balance >= amount) { balance = balance - amount return(True) } else { return(False) // Insufficient funds } } public getBalance() { return(balance) } }Private fields: balance, accountNumber Public procedures: deposit, withdraw, getBalance Q8. Why is it important to control access to data through procedures rather than allowing direct data access? Show Answer
- Validation:
withdraw()can check for sufficient funds before deducting- Invariants:
addStudent()invalidates the cache- Logging: Can add audit trails
- Flexibility: Can change internal implementation without affecting users
- Security: Prevents unauthorized or incorrect modifications
Advanced Questions
Q9. In the classroom example, what happens if we call
addStudent while average is executing (concurrent access)?Show AnswerThis causes a race condition (Topic 11). Both procedures might accessmarksListandaValuesimultaneously, leading to:
- Average might be computed with a partially updated list
aValuemight be set incorrectly- The list itself might get corrupted
This is why concurrent access needs atomicity (locking). Q10. Design a classShoppingCartthat encapsulates a list of items and provides procedures to add items, remove items, and compute total. Show AnswerjavaClass ShoppingCart { private items = [] // List of (itemName, price, quantity) public addItem(name, price, qty) { items = items ++ [(name, price, qty)] } public removeItem(name) { newItems = [] foreach item in items { if (item.name ≠ name) { newItems = newItems ++ [item] } } items = newItems } public total() { sum = 0 foreach item in items { sum = sum + (item.price * item.qty) } return(sum) } }
Q11. How does encapsulation help with the separation of interface and implementation?
Show AnswerEncapsulation enforces the separation by:
- Interface (public): Defines what operations are available (procedures)
- Implementation (private): Hides how those operations work
Changes to implementation (e.g., switching from list to dictionary internally) don't affect external code as long as the public interface stays the same. This is the contract concept from Week 3, now enforced by the language/notation. Q12. Compare and contrast the proceduralMaxMarks(fld)with an object-oriented approach. Show Answer
| Aspect | Procedural | OOP |
|---|---|---|
| Call | max = MaxMarks(Physics) | max = PhT.max() |
| Data | Passed as parameter | Stored in object |
| State | No retained state | Can cache max value |
| Multiple calls | Always recomputes | Can return cached value |
| Side effects | May reorder cards | Controlled, explicit |
| Naturalness | "Call a function on data" | "Ask the object for its max" |
The OOP approach feels more natural: instead of "computing the max of physics marks," it's "asking the Physics teacher object for the max."
📚 Cross-References
| Course | Topic | Connection |
|---|---|---|
| BSCS1002 (Python) | Week 11 — Classes | Python class, __init__, self |
| BSCS2002 (PDSA) | Week 10 — OOP | Encapsulation, inheritance |
Next Topic: 18 — Concurrency & Message PassingQuiz Tip: OOP questions ask you to identify what's private/public and trace state changes! Join Discord PreviousDepth-First Search (DFS)NextConcurrency, Message Passing & Race Conditions