Quiz 2

Week 10: OOP — Encapsulation & Abstraction

1983 words
10 min read
Python Week 1: the first filter for runtime behavior
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:
  1. State is external — data lives outside the procedure
  2. Side effects are unpredictable — any procedure can modify any data
  3. 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

pseudo
marksList = [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

ProblemExample
No connectionAverage doesn't "belong" to marksList
Global dataAny procedure could modify marksList
Repeated computationEach call to Average re-computes
No data hidingAnyone 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

BenefitDescription
ModularitySelf-contained units (objects)
Data hidingInternal details are hidden
State retentionObject remembers between calls
Cache/invariantsObject can store derived data
Natural mappingReal-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.
java
ClassAve (class)                    CT (object of ClassAve)
┌──────────────────────┐           ┌──────────────────────┐
│ Fields:              │           │ marksList: [85,72...]│
│   marksList          │    ──►    │ aValue: -1           │
│   aValue             │           │                      │
│ Procedures:          │           │ average() → compute  │
│   average()          │           │ addStudent()         │
│   addStudent()       │           └──────────────────────┘
└──────────────────────┘

Multiple Objects from One Class

pseudo
Class: 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).
sql
ClassAve {
    // Private fields (hidden from outside)
    private marksList
    private aValue
    // Public procedures (interface to outside)
    public average()
    public addStudent(newMark)
}

Why Hide Data?

ReasonExplanation
Prevent corruptionExternal code can't directly mess with internal data
Maintain invariantsObject controls access to ensure consistency
FlexibilityCan change implementation without affecting users
Reduced complexityUsers only need to understand the interface

Example: Why MarksList Should Be Private

If marksList were public:
pseudo
marksList = 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

sql
ClassAve {
    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

pseudo
CT = 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

AspectProceduralEncapsulated (OOP)
CallAveTotal = Avemarks(Total)AveTotal = CT.average()
CacheNot possible (no state)✅ Yes — stores result
DataPassed as parameterStored internally
Side effectsModify external dataControlled 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.
pseudo
Category (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

AspectProceduralEncapsulation (OOP)
Data locationExternal, passed as parametersInternal to object
StateNo retained state between callsObject retains state
CachingNot possible✅ Cache computed values
Data hidingNot possible✅ Private fields
Side effectsUnpredictable✅ Controlled via interface
Real-world mappingWeaker✅ Stronger
ComplexitySimpler for small programsBetter for large programs
ReusabilityVia proceduresVia classes (blueprints)

10. Practice Questions

Basic Questions

Q1. What is encapsulation?
Show Answer
Encapsulation 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 Answer
A 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 Answer
A 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 the ClassAve example, why is aValue set to -1 after addStudent? Show Answer
aValue caches the computed average. When a new student is added, the cached average is no longer accurate. Setting aValue = -1 (a sentinel value meaning "not computed") forces average() to recompute the value next time it's called.

Intermediate Questions

Q5. Explain how encapsulation enables caching in the ClassAve example.
Show Answer
In the procedural approach, each call to Average() must recompute the sum because there's nowhere to store the result. In the OOP approach, the object retains state between calls. The aValue field stores the computed average. On subsequent calls, average() checks aValue first — 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 class BankAccount with appropriate fields and procedures. Show Answer
java
Class 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
  1. Validation: withdraw() can check for sufficient funds before deducting
  2. Invariants: addStudent() invalidates the cache
  3. Logging: Can add audit trails
  4. Flexibility: Can change internal implementation without affecting users
  5. 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 Answer
This causes a race condition (Topic 11). Both procedures might access marksList and aValue simultaneously, leading to:
  • Average might be computed with a partially updated list
  • aValue might be set incorrectly
  • The list itself might get corrupted
This is why concurrent access needs atomicity (locking). Q10. Design a class ShoppingCart that encapsulates a list of items and provides procedures to add items, remove items, and compute total. Show Answer
java
Class 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 Answer
Encapsulation enforces the separation by:
  1. Interface (public): Defines what operations are available (procedures)
  2. 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 procedural MaxMarks(fld) with an object-oriented approach. Show Answer
AspectProceduralOOP
Callmax = MaxMarks(Physics)max = PhT.max()
DataPassed as parameterStored in object
StateNo retained stateCan cache max value
Multiple callsAlways recomputesCan return cached value
Side effectsMay reorder cardsControlled, 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

CourseTopicConnection
BSCS1002 (Python)Week 11 — ClassesPython class, __init__, self
BSCS2002 (PDSA)Week 10 — OOPEncapsulation, inheritance

Quiz 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
Document outline

Keep your place and jump directly to a heading.

Table of Contents
System Normal // Awaiting Context

Intelligence Hub

Navigate the knowledge graph to generate context. The Hub adapts dynamically to surface backlinks, related notes, and metadata insights.