Object-oriented programming
Bundle data with the code allowed to change it into objects, and let callers ask an object to do something without knowing how it does it.
3 technologies on this page ↓How it works
An object holds some state (its fields) together with the operations allowed on that state (its methods). Four ideas usually come with it. Encapsulation: outside code can only go through the methods, so the object can keep its own rules true; a cart can refuse a quantity of zero, and nothing else can reach in and set one. Polymorphism: many classes implement the same interface, say PaymentMethod.charge(), and the caller just calls the method; the language picks the right code at run time, which is called dynamic dispatch. Inheritance: a subclass reuses a parent class’s code and overrides parts of it. That ties the child to the parent’s internals, so the usual advice since the Design Patterns book is to favour composition: build objects out of smaller objects behind small interfaces and hand them in. Most mainstream languages (Java, C#, C++, Python, TypeScript) build all this on classes, but not all do: Go has methods and interfaces with no type hierarchy at all. Alan Kay, who coined the term, meant something narrower and more radical: objects as little computers that only talk by sending messages.
A vending machine. You press buttons and get a drink; you can’t reach in and rearrange the coins, and any machine with the same buttons works the same way for you, whatever is inside.
Reach for it when
- Long-lived things with rules to protect: an account, a cart, a document being edited
- Many variants behind one interface: payment methods, storage backends, UI widgets
- GUIs, games and simulations, where the program models things that each keep their own state
Think twice when
- Data pipelines and calculations, where data flows through steps and plain functions are simpler
- Deep inheritance trees built for code reuse; compose small objects instead
- Wrapping every action in a class (
OrderProcessorManagerFactory) when a function would do
A real example
A checkout accepts cards and bank transfers. Each is a class that implements PaymentMethod with one method, charge(cents). The Cart keeps its lines in a private field and exposes add(sku, qty), which refuses a quantity of 0 or less, so no other code can put a cart into a broken state. At checkout the cart is handed a PaymentMethod and calls charge; adding a wallet later means writing one new class, with no change to the cart.
Technologies
Specific products, and what each does differently.
What people mean by “object-oriented”#
The word covers several ideas that arrived at different times. Languages pick different subsets.
Encapsulation
Simula, 1967State is private and changed only through methods, so the object can enforce its own rules. TypeScript’s private is checked only at compile time; its #field is private at run time too.
Polymorphism
late bindingCallers depend on an interface, not a class. Which method runs is decided at run time by the object that receives the call.
Inheritance
subclassingA subclass reuses and overrides a parent’s code. Simula introduced it; Kay left it out of early Smalltalk until he understood it better. It couples child to parent, which is why it fell out of favour as the main reuse tool.
Composition
Design PatternsBuild behaviour by plugging small objects into bigger ones through interfaces. Erich Gamma calls this black-box reuse, and the Strategy pattern his prototypical example.
Messaging
Kay’s definitionObjects as cells or networked computers that only exchange messages, with state hidden and everything bound as late as possible. Closer to actors than to most class-based code.
In code · ts
interface PaymentMethod {
charge(cents: number): Promise<string>; // returns a receipt id
}
class Card implements PaymentMethod {
constructor(private token: string) {}
async charge(cents: number) { return `card:${this.token}:${cents}`; }
}
class BankTransfer implements PaymentMethod {
constructor(private iban: string) {}
async charge(cents: number) { return `transfer:${this.iban}:${cents}`; }
}
class Cart {
#lines = new Map<string, number>(); // hidden: only methods below can touch it
add(sku: string, qty: number) {
if (qty <= 0) throw new Error("qty must be positive"); // the cart guards its own rule
this.#lines.set(sku, (this.#lines.get(sku) ?? 0) + qty);
}
// composition: the cart is handed a PaymentMethod instead of subclassing one
async checkout(pay: PaymentMethod, priceOf: (sku: string) => number) {
let total = 0;
for (const [sku, qty] of this.#lines) total += priceOf(sku) * qty;
return pay.charge(total); // which charge() runs is decided at run time
}
}
const cart = new Cart();
cart.add("sku-17", 2);
cart.checkout(new Card("tok_9f3a"), () => 1250).then(console.log); // card:tok_9f3a:2500
cart.checkout(new BankTransfer("DE89..."), () => 1250).then(console.log); // transfer:DE89...:2500Often confused with
Where it came from1961–2014
Object-oriented programming started as a way to simulate the world. In 1961 Ole-Johan Dahl and Kristen Nygaard, at the Norwegian Computing Center in Oslo, began designing a language for describing simulations made of many dissimilar interacting parts. Simula I followed, and then Simula 67, a general-purpose language completed in 1967. Building on Algol 60’s blocks and Tony Hoare’s proposal for records, it introduced classes that bundle data with procedures, subclasses for reusing code, late binding, and objects created at run time. Dahl and Nygaard received the 2001 Turing Award “for ideas fundamental to the emergence of object oriented programming”.
Alan Kay, a graduate student at Utah after November 1966, saw Simula and Ivan Sutherland’s Sketchpad and imagined programs made of objects like biological cells or computers on a network, communicating only by messages. He says it was probably in 1967 that he first called it “object-oriented programming”. At Xerox PARC his group built Smalltalk (Smalltalk-72, then the release version, Smalltalk-80), a system built from objects that do everything by sending each other messages. Kay deliberately left inheritance out at first, and in 2003 he summed up: “OOP to me means only messaging, local retention and protection and hiding of state-process, and extreme late-binding of all things.”
The mainstream took Simula’s version. Bjarne Stroustrup wanted to write efficient systems programs in the style Simula encouraged, and started “C with Classes” in 1979; it became C++, first released commercially in October 1985. Sun announced Java on 23 May 1995, a language where every function had to live in a class. By the 1990s objects were the default way to teach and structure software, and the criticism grew with them: Erich Gamma and his co-authors advised favouring composition over inheritance, Joe Armstrong of the Erlang team argued that data and functions should never have been bound together, and Steve Yegge’s 2006 “Execution in the Kingdom of Nouns” mocked Java for wrapping every verb in a noun. Java itself added lambdas in Java 8 (2014), and most languages today are a mix of objects and functions.
Why it’s built this way
- Classes that bundle data with the procedures that act on it
- Simula was built to describe systems of many interacting parts. Making each part a class instance with its own data and procedures let a program mirror the system it simulated.
- Subclasses for reuse
- Simula 67 added subclasses, so a general class could be specialised without copying its code. Later practice found the coupling between parent and child brittle, which is why Gamma recommends small interfaces and composition.
- Messages and late binding instead of procedure calls
- Kay wanted objects that behaved like independent computers on a network, so representation could be hidden and changed. Deciding at run time which code answers a message is what makes that possible.
- Classes as the only unit of code (Java)
- Java followed Simula’s mechanisms more closely than C++ and had no free functions. It made programs uniform, and it is exactly what critics like Yegge attacked, until Java 8 added lambdas.
Timeline
- 1961
Dahl and Nygaard start work on a simulation language at the Norwegian Computing Center
- 1967
Simula 67 introduces classes, subclasses and objects; Kay coins “object-oriented”
- 1972
Smalltalk-72, the first real Smalltalk, runs at Xerox PARC
- 1979
Stroustrup starts “C with Classes”, which becomes C++ (released 1985)
- 1995
Sun announces Java
- 2001
Dahl and Nygaard receive the Turing Award for Simula
- 2014
Java 8 adds lambda expressions
- IEEE Milestone: Object-Oriented Programming, 1961–1967 (Simula, with the 2001 Turing Award citation)
- Alan Kay to Stefan Ram: on the meaning of “object-oriented programming” (email, Jul 2003)
- Alan Kay: The Early History of Smalltalk (HOPL-II, 1993)
- Bjarne Stroustrup’s FAQ: when C++ (first called “C with Classes”) was started and released
- InfoQ: Java at 30 (May 2025), on Sun’s announcement of Java on 23 May 1995
- Artima: Design Principles from Design Patterns, a conversation with Erich Gamma (Jun 2005)
- Joe Armstrong: Why OO Sucks (copy of the original essay)
- Steve Yegge: Execution in the Kingdom of Nouns (Mar 2006)
- OpenJDK JEP 126: Lambda Expressions & Virtual Extension Methods (delivered in Java 8)
- OpenJDK: JDK 8 (General Availability on 18 March 2014)
Sources9
- Alan Kay to Stefan Ram: on the meaning of “object-oriented programming” (email, Jul 2003)
- Alan Kay: The Early History of Smalltalk (HOPL-II, 1993)
- IEEE Milestone: Object-Oriented Programming, 1961–1967 (Simula, with the 2001 Turing Award citation)
- Artima: Design Principles from Design Patterns, a conversation with Erich Gamma (Jun 2005)
- TypeScript Handbook: Classes (implements clauses, private and #private fields)
- Go FAQ: Is Go an object-oriented language?
- Joe Armstrong: Why OO Sucks (copy of the original essay)
- Steve Yegge: Execution in the Kingdom of Nouns (Mar 2006)
- Martin Fowler: Anemic Domain Model (Nov 2003)