Courses / Computer Science I
Programming II

Abstract Data Use

Computer Science I 560 words Free to read

Using Data Without Knowing Its Insides

A powerful idea in programming is to separate what a piece of data does from how it does it. An abstract data type (ADT) is a data type defined by its operations and their behavior, not by its internal representation. A stack ADT, for instance, is defined by push, pop, and peek behaving in last-in-first-out order — regardless of whether it is implemented with an array or a linked list underneath.

The line between the operations a user may call and the hidden internals is the abstraction barrier (or interface). Code above the barrier uses only the published operations; code below implements them. This separation, called information hiding or encapsulation, has a great payoff: the implementation can be swapped for a better one (faster, less memory) without changing any code that uses the ADT, as long as the operations still behave the same.

This is why you can use a language's built-in list, dictionary, or set without knowing their internal machinery. You program against the interface — the promised operations and behavior — and trust the implementation to honor it. Designing good interfaces (small, clear, hard to misuse) is a central programming skill.

Common pitfall: reaching through the abstraction barrier to depend on an ADT's internal representation. If your code relies on how a stack happens to store its elements today, it breaks when the implementation changes. Use only the published operations; that independence from internals is the whole point of the abstraction.

Making an ADT Concrete

An abstract data type says what operations exist; a class is how most languages let you write one down. A class bundles fields (the internal data) with methods (the operations), and marks which of them are visible from outside. An object is one instance of a class — its own set of field values, sharing the class's methods with every other instance. The class is the blueprint; objects are the things built from it.

Creating an object is not merely setting memory aside. A constructor is the code that runs once, at creation, and its job is to leave the object in a valid state — to establish the class invariant, the property that must hold for the object to make any sense. If a BankAccount has the invariant "the balance is never negative", its constructor must reject or correct a negative opening balance. Every method may then assume the invariant on entry, and is obliged to restore it before returning.

Encapsulation is what makes that obligation enforceable. Fields are marked private, reachable only from inside the class; the public methods are the only way in. Without it no invariant is defensible, because any code could assign to balance directly and the constructor's check would count for nothing. The public methods, together with their promised behaviour, are the class's interface — and two entirely unrelated classes can offer the same interface while storing completely different things inside.

Common pitfall: making the fields public (or adding a getter and setter for every one) and treating the constructor as a place to merely copy arguments into them. That reduces a class to a bag of variables with extra syntax: nothing guards the invariant, so any caller can put the object into a state the class's own methods were written on the assumption could never arise.

Practise this lesson

The explanation above is free to read. The graded practice for this lesson lives in the Tryals app.

12practice questions
2interactive scenes
Start Computer Science I free

Programming II