Question bank — Composition — has-a relationship vs is-a
Two words you must have straight before starting:
- Composition = a class holds another object as a field and calls its methods (delegation). "has-a".
- Inheritance = a class is a kind of another class and must be usable wherever that parent is expected (Liskov). "is-a".
Two pictures to hold in your head
The whole page is a series of traps around which arrow you draw between two boxes. Fix the two arrows first.

Look at the figure: in is-a (left) the child box sits inside the parent's territory — it inherits the parent's whole surface, so a change to the parent ripples down. In has-a (right) the two boxes stay separate and only a thin arrow (a method call) connects them. That thin arrow is the entire dependency — that is why composition is looser.
The next figure turns that thin arrow into an actual call graph — who calls whom when car.start() runs:

Notice the caller only touches Engine's public method ignite(); it never reaches into the engine's internals. That single narrow contact point is what makes swapping the engine safe. Keep both pictures in mind as you answer below.
True or false — justify
Every answer is one or two sentences of reasoning — never a bare true/false.
"A Car that stores an Engine field is using inheritance."
class Car(Engine), which nonsensically claims a car is an engine."If two classes share code, one should inherit from the other."
"class Stack(list) is safe because push and pop behave correctly."
insert, indexing, and slicing are all public, so a user can poke the middle and violate LIFO even though your own methods are fine."A part held by composition can always be swapped at runtime, no matter how it was set up."
car.engine = ElectricEngine()); a part hard-created and never re-exposed inside the constructor is still composition but cannot be swapped from outside. Composition enables runtime swapping, it does not guarantee it."A part that is injected (passed into the constructor) or stored in a public/settable field can be swapped while the program runs."
car.engine = ElectricEngine()) takes effect immediately; this is the precise condition under which composition permits runtime swapping."Favoring composition over inheritance means never using inheritance."
Circle(Shape)), inheritance is the correct tool."A Person class with a name string field is an example of composition."
name is just state, not a collaborator you call methods on."Inheritance couples classes more tightly than composition."
"An amphibious robot built from a Flyer part and a Swimmer part needs its own dedicated class."
Robot([Flyer(), Swimmer()])) instead of writing a FlyingSwimmingRobot class."If A has-a B, then B is necessarily hidden from A's users."
_items in a Stack) is a separate encapsulation decision you make to protect invariants."Inheriting from an abstract base class or protocol (interface inheritance) is just as risky as inheriting from a concrete class."
Spot the error
State what is wrong and why, in reasoning terms.
The two boxes below are exactly the is-a / has-a arrows from the opening figure — for each "error" ask which arrow was drawn wrong.
"class Password(str) — a password is a string, so inherit."
upper, slicing, concatenation, __str__ that leaks it), so its secret is fully exposed and its validation rules can be bypassed; hold a string privately and expose only safe methods."class EmailQueue(list) because a queue is a list of emails."
append, insert, sort, and indexing, so FIFO ordering can be broken from outside; the queue has a list internally and should expose only enqueue/dequeue."class Car(Engine) so the car can call ignite() directly."
Car where an Engine is required), and it fuses the two lifecycles; the car should hold an engine and delegate start() to engine.ignite()."To reuse a Logger, I inherit: class Service(Logger)."
logger field and call self.logger.log(...)."I made Stack hold a list but also did class Stack(list) for convenience."
Stack itself, so the LIFO guarantee is still breakable."class Robot: def __init__(self): self.flyer = Flyer() — abilities are hard-coded, but it's still composition, so it's flexible."
"class PaymentGateway(AbstractGateway) where AbstractGateway is an abstract base with no code, only method signatures — 'this is risky inheritance.'"
charge(), refund(), etc., so there is no parent logic to break and this is a legitimate, safe use of inheritance.Why questions
"Why does the English 'is-a' test actually predict a correct type relationship?"
"Why is a changing parent class dangerous for inherited children but not for held parts?"
"Why does hiding the internal list fix the broken Stack?"
_items and publishing only push/pop/size, the dangerous middle-poking operations simply aren't reachable, so LIFO can't be violated."Why does composition avoid the 2^n class explosion that inheritance suffers?"
"Why is passing the engine in (rather than building it inside Car) worth the extra parameter?"
Car, decoupling the car from which concrete engine it uses."Why is 'a car has an engine' fine but 'a car has an animal' still nonsense?"
"Why is interface inheritance often considered compatible with 'favor composition', while implementation inheritance is the thing being warned against?"
Edge cases
"Is delegating to an object you never actually call methods on still composition?"
"What if a class holds a part AND is genuinely a subtype of something else?"
Circle(Shape) (true is-a) could also hold a Renderer (has-a); use inheritance for the substitutable kind-of relationship and composition for the swappable behavior."What happens to composition when the held part is None or not yet set?"
self.engine.ignite() raises on None), so a composed class must decide: require the part in the constructor, provide a safe default part, or guard before delegating."Can inheritance ever be the safer choice than composition?"
Shape/Circle), inheritance expresses intent more directly than manually re-delegating every method."Is a subclass that overrides every parent method still real inheritance, or disguised composition?"
"Two objects each hold a reference to the same shared part — is that still composition?"
"Where does an abstract base class / protocol sit on the composition-vs-inheritance line?"
Connections
- ← Back to parent topic
- Inheritance — is-a relationship
- Liskov Substitution Principle
- Encapsulation and Information Hiding
- Dependency Injection
- Strategy Pattern
- Aggregation vs Composition (UML)
- Fragile Base Class Problem