Base CS from zero
Abstraction: build a leak-proof-then-leaky module
Reading about interfaces, encapsulation, and leaks is not the same as feeling them hold and then break in your own code. Build one small module, prove its interface holds while you swap the guts underneath, then push it until it leaks — and write down exactly what showed through.
Turn the unit’s four ideas into one buildable thing: a module that exposes a tiny public interface, encapsulates its data so no caller can reach it, lets you replace the hidden implementation with callers untouched, and then demonstrates a leak you can name and explain.
Build a Stack as a self-contained module with a fixed public interface (push, pop, peek, size) that fully encapsulates its data, then prove the abstraction by swapping its internal implementation without changing one line of caller code — and finish by deliberately making the abstraction leak and documenting the leak.
- A short README listing the public interface (the four exported names) and stating explicitly which names are private — and why a caller cannot reach them.
- Evidence (a screenshot, a paste of output, or a failing line with its error) that the caller cannot read or overwrite the private storage from outside the module.
- The same caller program runs unchanged against at least two different internal implementations and produces identical output — shown side by side.
- A one-paragraph write-up of the leak: what you did to trigger it, what detail of the lower layer showed through, and why this matches the Law of Leaky Abstractions (the abstraction was useful AND it leaked at its limit).
- Add an invariant the module enforces internally (e.g. size never goes negative; pop on empty throws a clear error instead of corrupting state) and show a caller cannot violate it from outside.
- Add a third implementation with a different performance profile and a one-line note on how the interface stayed fixed while the cost characteristics changed — a hint that even a held interface can leak through speed.
- Write a tiny test file that exercises only the public interface, then show the same tests still pass after each implementation swap — tests against the interface, not the internals.
- Document a second leak of a different kind (a slow operation, or a maximum-size limit) and contrast it with the first: same law, different way the lower layer surfaced.
This is the loop the unit was built for, in your own code: expose a small fixed interface, encapsulate the data so the boundary is enforced not merely promised, and prove the abstraction by swapping the hidden implementation with callers untouched. Namespacing lets two modules share a short name without clashing. And the closing leak is the honest part — you made a real, useful abstraction surface the layer below at its limit, named the leak, and saw why the Law of Leaky Abstractions holds: the abstraction was worth using AND it leaked, both at once.