Neural Sync Active
Week 3: Side Effects of Procedures
Registry Synced
Week 3: Side Effects of Procedures
2538 words
13 min read
Reading compass
Now · 1. Motivation: What Happens to the Data?
Week 3: Side Effects of Procedures
BSCS1001 — IIT Madras BS Degree Prerequisite: Topic 05 (Procedures & Parameters) Cross-links: BSCS1002-Python (Week 5 — Function Side Effects), BSCS2002-PDSA (Week 3 — Purity)
1. Motivation: What Happens to the Data?
You write a procedure to compute the sum of Maths marks. You pass in a carefully sorted deck of cards (arranged by total marks, descending). After the procedure runs... the deck is in a different order.
Did the procedure mess up your data?
This question — "what state is the data in after a procedure runs?" — is the core of side effects.
Real-world analogy: You lend a friend a book. You expect it back in the same condition (no side effects). But if your friend is a bookbinder who repairs torn pages, you might want them to fix things (desirable side effect). The key is knowing what to expect.
2. What is a Side Effect?
A side effect occurs when a procedure modifies some data during its computation, beyond just returning a value.
(Diagram)
Examples of Side Effects
| Side Effect | Example |
|---|---|
| Reordering cards | After iteration, cards are in Pile 2 (reverse order typically) |
| Modifying a list | Adding/removing items from a list passed as parameter |
| Changing a dictionary | Adding/removing key-value pairs |
| Writing to a file | Saving results to disk |
| Printing output | Displaying something on screen |
The Key Question
Does the caller care if the data is modified?
| Sometimes... | The side effect... |
|---|---|
| ✅ Doesn't matter | Adding marks — card order irrelevant |
| ✅ Is the GOAL | Sorting the deck — the whole point |
| ❌ Is a problem | Finding max marks but losing card order |
3. The Card Deck: A Concrete Example
Recall our standard iteration pattern:
sqlwhile (Pile 1 has more cards) { Pick a card X from Pile 1 Move X to Pile 2 // Process X }
What Happens to the Deck?
| Before Procedure | After Procedure |
|---|---|
| Pile 1: [1, 2, 3, 4, 5] | Pile 1: [] |
| Pile 2: [] | Pile 2: [5, 4, 3, 2, 1] |
The deck has been reversed! Cards that were in order [1,2,3,4,5] are now in order [5,4,3,2,1].
Does the Reversal Matter?
Case 1: Summing marks → No!
1+2+3+4+5 = 5+4+3+2+1 = 15. Order doesn't affect addition.
Case 2: Finding max → No! Max is the same regardless of order.
Case 3: Checking for a pattern that depends on position → Yes! If the original order encodes information (e.g., position in class), reversal destroys it.4. Desirable Side Effects
Sometimes the side effect is the purpose of the procedure.
Example: Sorting the Deck
pseudoProcedure SortDeck() { // Rearrange cards in descending order of Total marks // The side effect (rearranging) is the whole point! }
Example: Deleting a Key from a Dictionary
pseudoProcedure DeleteKey(d, k) { myd = {} foreach key in keys(d) { if (k ≠ key) { myd[key] = d[key] } } d = myd // Side effect: d is modified End DeleteKey
Example: Adding a New Student
pseudoProcedure AddStudent(newMark) { marksList = marksList ++ [newMark] // Side effect: list grows aValue = -1 // Side effect: cache invalidated End AddStudent
When Side Effects Are Desirable
| Situation | Why It's OK |
|---|---|
| Sorting data | The whole point is to rearrange |
| Updating a record | You want the data to change |
| Accumulating in a passed list | The caller expects the list to grow |
| Caching/computing derived values | Speed up future operations |
5. Undesirable Side Effects
Sometimes the side effect causes problems for the caller.
Example: Pronoun Resolution
In Week 6, we resolve pronouns to their matching nouns. The procedure requires the lists to be in sorted order (by serial number). If a procedure rearranges these lists as a side effect, the pronoun matching will fail.
pseudo// This procedure has an UNDESIRABLE side effect: Procedure FindOverlap(11, 12) { overlap = [] foreach x in 11 { foreach y in 12 { if (x == y) { overlap = overlap ++ [x] } } } // Side effect: 12 has been consumed/restructured! return(overlap) End FindOverlap
Why Undesirable Side Effects Are Dangerous
(Diagram)
The caller assumed the data would be preserved. The procedure broke that assumption.
6. Interface vs Implementation
This is one of the most important concepts in the course.
The Interface
The interface is the contract — what the procedure promises to do.
| Aspect | Description |
|---|---|
| Parameters | What inputs are needed |
| Return value | What is computed and returned |
| Side effects | What modifications (if any) are made |
| Guarantees | What assumptions the caller can rely on |
The Implementation
The implementation is how the procedure achieves its contract — the actual code inside.
Why Separate Interface from Implementation?
(Diagram)
Key principle: You can change the implementation as long as the interface stays the same. The caller shouldn't need to know — or care — about implementation details.
Example
sql// Interface: Find maximum of a field // Parameters: fld - the field to check // Returns: the maximum value found // Side effect: Cards are moved from Pile 1 to Pile 2 Procedure MaxMarks(fld) { // Implementation can be anything that satisfies the interface Max = 0 while (Pile 1 has more cards) { Pick a card X from Pile 1 Move X to Pile 2 if (X.fld > Max) { Max = X.fld } } return(Max) End MaxMarks
The interface tells the caller: "You'll get the maximum, but your cards will end up in Pile 2." If the caller needs to preserve card order, they should make a copy first.
7. The Procedure Contract
Every procedure comes with a contract that specifies:
(Diagram)
Contract Examples
Contract A: SumMarks — No side effects matter
pseudoFunctionality: - Parameters: gen (gender), fld (field name) - Returns: Sum of fld for students of gender gen Data Integrity: - Side effect: Cards are moved to Pile 2 (doesn't affect computation) - Predictable: Yes — deck will be reversed
Contract B: DeleteKey — Side effect is essential
sqlFunctionality: - Parameters: d (dictionary), k (key to delete) - Returns: nothing (void) Data Integrity: - Side effect: Key k is removed from dictionary d - Predictable: Yes — exactly one key removed
Contract C: PronounMatcher — Side effects NOT tolerated
pseudoFunctionality: - Parameters: nounList, pronounList (both sorted) - Returns: Matched pairs Data Integrity: - Side effect: NONE — input lists must remain sorted - Guarantee: Input lists are NOT modified
8. Side Effects with Collections
Lists and Side Effects
When a procedure receives a list, modifying it is a side effect:
pseudoProcedure AddItem(myList, item) { myList = myList ++ [item] // Side effect: modifies the list End AddItem
Avoiding Side Effects with Lists
To avoid side effects, work on a copy:
pseudoProcedure AddItemSafe(myList, item) { newList = myList // Make a copy newList = newList ++ [item] // Modify the copy return(newList) // Return the modified copy End AddItemSafe
The Side-Effect-Free Pattern
sql// WITH side effect (procedure modifies input) Procedure DeleteKey(d, k) { foreach key in keys(d) { if (k == key) { remove key from d // d is changed! } } } // WITHOUT side effect (procedure returns new dictionary) Procedure DeleteKey2(d, k) { myd = {} foreach key in keys(d) { if (k ≠ key) { myd[key] = d[key] // Building new dictionary } } return(myd) // Original d is unchanged End DeleteKey2 // Caller must reassign: myd = DeleteKey2(myd, k) // Caller explicitly updates reference
9. Managing Side Effects
Best Practices
| Practice | Description | Example |
|---|---|---|
| Document side effects | State them in the contract | "Note: modifies the input list" |
| Make copies | Work on copies when caller needs original | newList = oldList |
| Use pure functions | No side effects at all | Return new data instead of modifying |
| Minimize scope | Only modify what you must | Don't touch unrelated data |
| Be predictable | Same inputs → same side effects | Don't surprise the caller |
Decision Flowchart
(Diagram)
10. Comparison Table
Pure vs Impure Procedures
| Aspect | Pure Procedure | Impure Procedure |
|---|---|---|
| Side effects | None | Has side effects |
| Deterministic? | Yes (same inputs → same output) | May vary based on state |
| Testing | Easy (no state to manage) | Harder (need to set up state) |
| Predictability | Very predictable | Less predictable |
| Example | MaxMarks(fld) | AddStudent(newMark) |
| Caller concern | Just the return value | Return value + state changes |
Desirable vs Undesirable Side Effects
| Aspect | Desirable | Undesirable |
|---|---|---|
| Is it expected? | Yes, caller knows | No, caller is surprised |
| Is it documented? | Yes, in contract | No, or poorly documented |
| Does it help? | Yes, it achieves the goal | No, it creates problems |
| Example | Sorting a list | Reversing a sorted list |
| How to handle | Document and embrace | Refactor to avoid |
11. Practice Questions
Basic Questions
Q1. What is a side effect in a procedure?
Show AnswerA side effect occurs when a procedure modifies some data during its computation, beyond just returning a value. Examples: reordering cards, modifying a list, changing a dictionary. Q2. Give one example of a desirable side effect and one example of an undesirable side effect. Show Answer
Desirable: Sorting a deck of cards (the rearrangement IS the goal) Undesirable: A procedure that finds max marks but accidentally reverses the deck, destroying the original order that another procedure relied on. Q3. What is the difference between a procedure's interface and its implementation? Show Answer Interface — the contract: what parameters, what return value, what side effects Implementation — the actual code inside the procedureYou can change the implementation without affecting the caller, as long as the interface stays the same. Q4. In the standard iteration pattern, what side effect occurs to the card deck? Show AnswerCards are moved from Pile 1 to Pile 2. Since cards are picked from the top of Pile 1 and placed on top of Pile 2, the deck ends up in reverse order compared to the original.
Intermediate Questions
Q5. Explain why the following code has a side effect and whether it's desirable:
pseudoProcedure DoubleList(L) { i = 0 while (i < length(L)) { L[i] = L[i] * 2 i = i + 1 } End DoubleList
Show AnswerSide effect: The input list L is modified — each element is doubled.Is it desirable? That depends on the contract. If the procedure is called "DoubleList" and the caller expects L to be modified, then YES. But if the caller expects a new list to be returned (and L untouched), they would be surprised.Better design: Either:
- Document: "Side effect: modifies L in place"
- Or make it pure: create and return a new list Q6. Rewrite
DeleteKeyso it has NO side effects (pure function). Show AnswerpseudoProcedure DeleteKeyPure(d, k) { newDict = {} foreach key in keys(d) { if (key ≠ k) { newDict[key] = d[key] } } return(newDict) End DeleteKeyPure // Usage: myDict = DeleteKeyPure(myDict, "someKey") // Original myDict is unchanged; we reassign the result
Q7. If a procedure has an undesirable side effect, what are two ways to fix it?
Show Answer
Work on a copy: Inside the procedure, copy the input data and work on the copy. Return the modified copy instead of changing the original. Document it: If the side effect cannot be avoided, clearly document it in the procedure's contract so the caller knows what to expect.
Q8. Consider: procedure A sorts the deck, then calls procedure B to find the average. After both run, what state is the deck in?
Show AnswerThe deck is in whatever state procedure A left it (sorted, if B doesn't rearrange). But the standard iteration pattern in B moves cards from Pile 1 to Pile 2, which reverses them. If A sorted descending, after B the cards are in ascending order (since Pile 2 is reversed from Pile 1).This is a classic example of unexpected interaction between side effects.
Advanced Questions
Q9. Design a procedure contract for a function
FindCommonElements that takes two sorted lists and returns their intersection. Specify parameters, return value, AND side effects.Show Answerpseudo// Contract for FindCommonElements // Parameters: // list1 - sorted (ascending) list of integers // list2 - sorted (ascending) list of integers // Returns: // A new list containing elements present in both list1 and list2 // Side effects: // NONE - input lists are NOT modified // (Internal implementation uses first() and rest() which modifies // the list copy, not the original) Procedure FindCommonElements(list1, list2) { common = [] // Implementation that avoids side effects... return(common) End FindCommonElements
Q10. Trace the side effects in this sequence:
pseudo1. Create list L = [3, 1, 4, 1, 5] 2. Call Sort(L) // Sorts L ascending 3. Call Reverse(L) // Reverses L 4. Call Max(L) // Finds max
What is L after each step? Which side effects are desirable?
Show Answer
| Step | L after step | Side effect desirable? |
|---|---|---|
| Start | [3, 1, 4, 1, 5] | — |
| After Sort(L) | [1, 1, 3, 4, 5] | ✅ Yes (sorting is the goal) |
| After Reverse(L) | [5, 4, 3, 1, 1] | ✅ Yes (reversing is the goal) |
| After Max(L) | [5, 4, 3, 1, 1] (unchanged) | ✅ No side effect (pure function) |
Final L = [5, 4, 3, 1, 1] (reversed from original) Q11. Why is it important to document side effects in a procedure's contract? Show Answer
- Caller awareness — The caller needs to know if their data will be modified
- Correctness — The caller can account for side effects in subsequent code
- Debugging — If something goes wrong, documented side effects help trace the issue
- Maintainability — Future changes to the procedure must preserve the contract
- Reusability — Other programmers can use the procedure correctly
Without documentation, callers might assume their data is safe when it isn't. Q12. In the classroom dataset example (Week 10),addStudentresetsaValueto -1 as a side effect. Explain why this side effect is both desirable and potentially dangerous in a concurrent context. Show AnswerDesirable because: When a new student is added, the cached average (aValue) becomes stale. Resetting it to -1 forcesaverage()to recompute the correct value. This is a necessary side effect for correctness.Dangerous because (concurrent context): Ifaverage()is running at the same time asaddStudent(), there's a race condition. The average might readaValuewhileaddStudentis changing it, getting an incorrect result. Oraveragemight compute using themarksListwhileaddStudentis appending to it — leading to corrupted data.This is why concurrent access needs atomicity (non-concurrent access to shared state).
📚 Cross-References
| Course | Topic | Connection |
|---|---|---|
| BSCS1002 (Python) | Week 5 — Functions | Mutable vs immutable arguments |
| BSCS2002 (PDSA) | Week 3 — Modularity | Pure functions vs procedures |
| BSCS2002 (PDSA) | Week 8 — Graphs | Side effects in graph algorithms |
Next Topic: 07 — Nested IterationsQuiz Tip: Side effect questions ask you to predict what state data is in after a procedure. Always trace the deck/card movements! Join Discord PreviousProcedures & ParametersNextNested Iterations