Abstraction and Information Hiding

advanced40 min

Learning objectives

  • Explain abstraction and information hiding with technical precision, beyond a bare definition
  • Explain why a given abstraction remains valid even as its implementation changes
  • Justify the importance of abstraction and information hiding in software development

Learn

AQA 4.4.3 — Abstraction and information hiding

Retrieval: Year 12's introduction-to-computational-thinking defined abstraction as choosing which details matter for a purpose. This lesson goes further: precisely why a chosen abstraction remains valid, and the specific software-engineering discipline — information hiding — built directly on top of it.

Key vocabulary

  • Interface — what a piece of software promises to do, from the outside: what it takes in, what it produces.
  • Implementation — how that promise is actually carried out internally.
  • Information hiding — deliberately preventing code outside a component from depending on its internal implementation detail, exposing only its interface.

Understand — what is being abstracted, and why the abstraction is valid

Python's own sorted() function is a genuine abstraction: calling sorted(my_list) hides which specific sorting algorithm runs internally (in CPython, a highly-tuned hybrid called Timsort) — the caller only needs to know the interface: give it an iterable, it returns a new sorted list. This abstraction is valid precisely because the interface's contract — "give me an iterable, I'll return it sorted" — is all that any caller actually relies on. As long as that contract keeps holding, the internal implementation is free to change (Python genuinely has changed its internal sorting algorithm across versions) without breaking a single line of code that merely calls sorted().

See it — information hiding in a Book class

class Book:
    def __init__(self, title, author, isbn):
        self.title = title
        self.author = author
        self.isbn = isbn
        self._times_borrowed = 0   # implementation detail

    def borrow(self):
        self._times_borrowed += 1
        return f"You have borrowed {self.title}."

    def times_borrowed(self):
        return self._times_borrowed

Code that uses a Book object only needs to know its interface (borrow(), times_borrowed()) — not that _times_borrowed exists, or how it's incremented internally. Sequence 11's encapsulation lesson covered this same idea from the angle of protecting internal state; this lesson names the broader principle it's one specific application of.

Reason about what is deliberately discarded

Calling code deliberately never sees: how _times_borrowed is stored, whether borrow() does any other bookkeeping internally, or how the object's memory is laid out. None of this is "unimportant" in any absolute sense — it matters enormously to whoever writes the Book class — but it's deliberately irrelevant to anyone who merely uses one, and hiding it is precisely what lets the class's internals be improved later without breaking every piece of code that calls borrow().

Common mistake

Assuming information hiding means "the hidden details don't matter." They matter completely to the person maintaining that specific component — hiding only means other code, outside that component, is never allowed to depend on them, so they're free to change without breaking anything external.

Why this matters for the NEA

A class or module with a clean, well-designed interface — one that hides its own internal implementation detail from the rest of the program — is exactly the kind of software-engineering discipline AQA's NEA marking rewards, because it demonstrates genuine understanding of why the structure exists, not merely that classes were used.

Check your understanding

A programmer changes a Stack class's internal storage from a Python list to a different structure entirely, without changing its push(), pop() or is_empty() methods' behaviour. Explain why this change is valid, and identify what would make an equivalent change invalid. (3 marks)

(Valid because the Stack's interface - what push(), pop() and is_empty() promise to do - is completely unchanged; any code that only ever calls those methods cannot tell the difference. It would become invalid if the change altered the INTERFACE'S own promised behaviour - for example, if pop() started returning items in a different order, or push() started silently rejecting some values it previously accepted - since that would break the contract external code was relying on, not just the hidden implementation.)

Challenge

Identify a real system you use (a music app, an online shop) and describe its interface (what you can do with it) versus its implementation (how it actually works internally, as far as you can reasonably guess). Explain one genuine reason the implementation could change without you, as a user, ever noticing.

Looking ahead: the next lesson names two specific, genuinely different forms abstraction takes in software: procedural and functional abstraction.

Test yourself

Check your understanding with exam-style questions.

Go to Exam Practice
Log in to track this lesson on your progress dashboard.
Log in