Skip to content

Commit 8a06f13

Browse files
author
Bruce Eckel
committed
20
1 parent b40650f commit 8a06f13

2 files changed

Lines changed: 9 additions & 24 deletions

File tree

Chapters/20_Rethinking_Objects.md

Lines changed: 8 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -58,31 +58,29 @@ The industry has been quietly walking back from "everything is an object" and fr
5858
## The Liskov Substitution Principle {#liskov-substitution}
5959

6060
The *Liskov Substitution Principle* (LSP)
61-
says that an object of a subtype must work anywhere code expects an object of its base type,
62-
without breaking the program.
63-
A subclass may add behavior, but it must honor the base class's contract.
61+
says that an object of a subtype must work anywhere code expects an object of its base type.
62+
A subclass may add behavior, but it must honor the base class contract.
6463
It accepts the same arguments, returns the same kinds of results,
6564
and raises no surprising exceptions.
6665
When subclasses obey it,
6766
code written against the base class works unchanged on any of them.
6867
This is what makes polymorphism,
6968
and patterns like the [Template Method](25_Template_Method.md), safe.
70-
A statically typed compiler can check part of it,
71-
that an override's signature stays compatible,
72-
but not whether the override actually behaves the way the base class promises.
69+
A statically typed compiler can check that an override's signature stays compatible.
70+
It cannot check whether the override actually behaves the way the base class promises.
7371
The base class calls a method and trusts every subclass to stand in for it.
7472

75-
Python has no compiler to enforce even that structural check.
76-
Nothing stops a subclass from breaking the base class's contract.
73+
Python has no compiler to enforce that structural check.
74+
Nothing stops a subclass from breaking the base class contract.
7775
The interpreter runs code that violates the LSP without objection.
7876
That code may or may not fail at run time.
7977

8078
## Encapsulation Leaks
8179

8280
The first OOP promise is encapsulation: hide the data,
8381
expose it only through methods you control.
84-
In Python the usual move is a leading underscore and a read-only property.
85-
It does not work as well as it looks.
82+
Python hides a field with a leading underscore and a read-only property.
83+
This does not work as well as it looks.
8684
A getter that returns a mutable object hands the caller a reference to the underlying internals:
8785

8886
```python
@@ -125,19 +123,6 @@ the identical object the underscore was hiding.
125123
Python's `return` hands out references, never copies.
126124
The property blocked reassigning `numbers`,
127125
but it could not stop the caller from mutating the list it returned.
128-
129-
Testing shows the leak:
130-
131-
```python
132-
# test_leaky.py
133-
from leaky import Leaky
134-
135-
def test_getter_leaks_internal_state() -> None:
136-
leaky = Leaky([1, 2])
137-
leaky.numbers.append(999) # Changes the internal list
138-
assert leaky.numbers == [1, 2, 999]
139-
```
140-
141126
Mutating the returned list manipulates the internal state.
142127

143128
## Plugging Leaks Is Tedious

NOTES.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Chapter 20 might need "## What Is Polymorphism?"
22

33
"happen" "is what" "does it" "ever" "at all" "only"
4-
"was to" "in the first place" "already"
4+
"was to" "in the first place" "already" "even"
55

66
if __name__ == "__main__":
77
main()

0 commit comments

Comments
 (0)