Zum Inhalt springen

The OOP Revolution: Objects All the Way Down

Zusammenfassung

Object-oriented programming is the dominant paradigm in software engineering — not because it is theoretically optimal, but because it provided a cognitive model for organizing complexity that matched how humans think about systems. Its lineage runs from Simula’s 1967 insight that data and behavior belong together, through Smalltalk’s radical vision that everything should be an object exchanging messages, to C++’s pragmatic grafting of those ideas onto C, to Java’s successful democratization of OOP for the enterprise. Along the way, OOP generated both the most successful software engineering tools in history and some of its most spectacular failures — a pattern that recurs whenever a paradigm is elevated from technique to ideology.

Simula: The First Objects

In 1965, two Norwegian researchers at the Norwegian Computing Center, Ole-Johan Dahl and Kristen Nygaard, were building simulations of ship movements in Oslo harbor. Their problem was the standard problem of complex simulation: the code that described each ship’s behavior was tangled with the code that managed the simulation clock, which was tangled with the code that tracked collisions. Every change required understanding the entire system.

Their solution, formalized in the language Simula 67 (1967), was the class: a template that bundled together a data structure (a ship’s position, speed, heading) with the procedures that operated on that data (move, turn, stop). Instances of a class — objects — carried their own state and responded to messages in ways defined by their class. Simula also introduced inheritance: a FreighterShip class could extend a generic Ship class, inheriting its behavior and adding its own.

These concepts — class, object, inheritance, method — became the vocabulary of object-oriented programming. Dahl and Nygaard published papers; the ideas circulated within the research community; and for nearly a decade, almost nothing happened commercially.

Smalltalk: The Pure Vision

In 1972, Alan Kay at Xerox PARC designed Smalltalk from first principles as an object-oriented language for children. Kay’s vision was more radical than Simula’s: in Smalltalk, everything was an object — numbers, classes, classes of classes. There was no distinction between primitive values and compound objects. Computation proceeded entirely through messages: an object sent a message to another object, which responded according to its implementation. Even control flow — if statements, loops — was implemented through messages to Boolean objects.

Smalltalk was also the first language to integrate a graphical development environment. The Smalltalk system included what we now call an IDE: a class browser that showed the inheritance hierarchy, an inspector that showed an object’s live state, a debugger that let you modify code while the program ran and continue execution. When Steve Jobs visited Xerox PARC in 1979 and saw the Alto’s graphical interface, he was seeing a Smalltalk application. The graphical revolution and the OOP revolution have the same origin.

Smalltalk never became commercially dominant. Its pure-message-passing model was elegant but slow on 1970s and 1980s hardware. Its insistence on complete Smalltalk environments — you did not write Smalltalk programs, you modified a living Smalltalk image — made integration with other software difficult. But Smalltalk trained a generation of programmers who carried its ideas into every subsequent language they designed.

C++: OOP Goes to Work

Bjarne Stroustrup encountered Simula during his PhD research at Cambridge in the mid-1970s and found its class model genuinely useful for structuring complex systems programs. He also found Simula too slow and Smalltalk too ideologically pure for systems programming. His solution, developed at Bell Labs starting in 1979, was C with Classes — later renamed C++ (1983).

C++ grafted OOP concepts onto C: classes, inheritance, virtual functions (runtime polymorphism), and eventually templates (compile-time generics). Crucially, it added zero-cost abstraction as a design principle: a C++ class with no virtual functions should compile to code identical to hand-written C struct operations. This made C++ acceptable to systems programmers for whom performance was non-negotiable.

C++ became the language of choice for applications software through the late 1980s and 1990s — Microsoft Word, Adobe Photoshop, most game engines, and virtually all systems software that was too performance-sensitive for COBOL or too complex for C. Its complexity also became notorious: the language accumulated features across successive standards (C++98, C++03, C++11, C++14, C++17, C++20) until it was frequently described as multiple different languages occupying the same syntax. Stroustrup himself acknowledged that C++ was a tool that could be wielded with great skill or great damage.

The Four Pillars

OOP textbooks traditionally describe four properties as defining the paradigm:

  • Encapsulation: data and behavior bundled together; internal state hidden from outside code
  • Inheritance: child classes extend parent classes, reusing and specializing behavior
  • Polymorphism: a single interface describes behavior across multiple concrete types
  • Abstraction: complex implementations hidden behind simple interfaces

Alan Kay later said he considered messaging — not classes or inheritance — the central idea of OOP, and that C++ and Java had missed this point entirely. The debate about which of these properties is actually essential to “real” OOP has consumed conferences for decades with no resolution.

Java: OOP for the Million

James Gosling at Sun Microsystems designed Java (1995) for a world that C++ was failing to serve. C++ code was notoriously difficult to write safely: buffer overflows, dangling pointers, memory leaks, and undefined behavior were endemic. C++ programs were not portable — “compile once, debug everywhere” was the joke. And C++’s complexity made it accessible only to skilled practitioners.

Java’s answer was a managed runtime: a Java Virtual Machine (JVM) that ran portable bytecode, managed memory through garbage collection, enforced array bounds, and eliminated pointer arithmetic. “Write once, run anywhere” was the promise. OOP was enforced more strictly than in C++: in Java, almost everything was a class (the exception being primitive types, a compromise that haunted the language). The standard library was vast and well-documented.

Java’s timing was perfect for the web era. Netscape’s early idea of running Java applets in browsers did not survive (they were slow, insecure, and required plugin installation), but Java became the dominant language for server-side web development — running more internet back-ends than any other language through the early 2000s. The Spring Framework (2002), providing dependency injection and aspect-oriented programming on top of Java, became the architecture for most enterprise Java systems. The Android mobile platform, launched 2008, ran on a Java-compatible virtual machine — making Java the world’s most-used programming language by sheer number of deployed devices.

Design Patterns and the Formalization of OOP

The Gang of Four book — Design Patterns: Elements of Reusable Object-Oriented Software (1994) by Gamma, Helm, Johnson, and Vlissides — attempted to capture recurring solutions to common OOP design problems: Factory, Singleton, Observer, Strategy, Decorator, and twenty others. It became the most influential software engineering book of the 1990s and introduced a shared vocabulary for OOP architects.

The patterns book also revealed OOP’s limits. Many of the patterns existed to work around constraints of static, class-based OOP — particularly Java’s inflexibility. A Factory pattern is necessary in Java because you cannot pass a constructor as a function argument. In a language with first-class functions, Factory is just a function. By 2010, critics pointed out that the Design Patterns book was partly a catalog of Java’s missing features.

Dead End: OOP as Silver Bullet

The 1990s saw OOP applied as a universal solution. Relational databases were replaced with object databases (ObjectStore, Versant) in which persistent data was stored as object graphs rather than tables. The Object Management Group (OMG) produced standards for distributed object communication (CORBA, 1991) that were supposed to allow objects running on different machines to exchange messages transparently. Object databases mostly disappeared, unable to match the query performance of relational systems. CORBA became notorious as an over-engineered standard that nobody could implement correctly and nobody could use simply.

More broadly, OOP’s inheritance model proved brittle at scale. Deep inheritance hierarchies became maintenance nightmares: the Fragile Base Class Problem meant that changing a parent class in ways that seemed safe could break all its children unpredictably. “Favor composition over inheritance” became a standard piece of advice precisely because inheritance — OOP’s central feature — was so often misapplied. The functional programming renaissance of the 2010s was in part a reaction to the complexity that decade-old OOP systems had accumulated: immutable data, pure functions, and algebraic types were offered as alternatives to objects tangled in mutable shared state. Modern languages like Rust and Go are OOP-adjacent without enforcing inheritance; Python and JavaScript are multiparadigm. The lesson was not that OOP was wrong, but that no single paradigm should be applied to every problem.


📚 Sources