Why Message Passing Lost the OOP War (But May Still Win the Future)
When Alan Kay coined the term object-oriented programming (OOP), his vision wasn’t about classes, inheritance, or design patterns. It was about independent objects communicating via message passing, much like biological cells or actors in a system. Yet, somehow, that idea got buried beneath layers of class hierarchies, composition, and method overloading.
So what happened? Why did message-passing OOP, the original ideal, get sidelined? And what can we learn from its journey?
The Original Vision: Objects as Independent Agents
Alan Kay’s inspiration came from biology and Lisp. Objects were supposed to be self-contained, capable of maintaining their own state, and interacting only through messages. These weren’t “bags of data with methods”—they were mini-programs, processing requests in their own way, possibly in parallel, and capable of evolving independently.
In short, OOP was meant to model behavior, not just structure.
Why the Vision Didn’t Catch On
1. Hardware Realities and Performance Constraints
In the 1970s and 80s, computing power was limited. Message-passing systems were slower and more memory-hungry than direct method calls on class instances. Meanwhile, languages like C++ prioritized performance and determinism, offering a “good enough” version of OOP that fit neatly into the imperative, stack-based paradigm of the time.
The result? Message passing was seen as too abstract, too slow, and too different.
2. Class-Based OOP Was Easier to Teach and Learn
For most developers (and universities), it was easier to teach students that a “Dog is an Animal” than to explain asynchronous messaging between agents. Inheritance trees, object models, and method binding were concrete and visual.
Message passing, by contrast, was conceptual and often runtime-bound, making it feel more like dynamic magic than engineering.
3. The Languages That Popularized OOP Took a Different Path
Smalltalk, the most faithful implementation of Kay’s vision, never became mainstream. Instead, Java, C++, and later C#—which all leaned heavily on class-based OOP—became the norm in enterprise, education, and tooling.
These languages emphasized encapsulation and polymorphism, but the messaging aspect was either hidden (method calls) or nonexistent.
4. Tooling and IDE Ecosystems Rewarded Class-Centric Design
Static languages enabled powerful tooling: autocomplete, static analysis, refactoring tools, and early compilers. These required rigid structure and predictability. Message-passing models, often dynamic and late-bound, made these tools harder to build.
In other words: IDEs loved Java. They struggled with Smalltalk or Lisp-like flexibility.
5. Message Passing Wasn't Urgently Needed
Most early applications were single-threaded, running on a single machine. The concurrency and fault tolerance benefits of message passing were overkill for desktop GUIs, CRUD apps, or early web servers.
It wasn’t until later—when distributed systems, multi-core CPUs, and asynchronous UIs became the norm—that the strengths of message passing started to matter again.
What We Might Have Missed
The overemphasis on classes and inheritance led to some problematic patterns:
- Tight coupling between classes
- Rigid hierarchies that were hard to change
- Inheritance abuse, where behavior was inherited that shouldn’t have been
- The fragile base class problem
- Lack of natural concurrency and resilience
The message-passing model, by contrast, naturally leads to loose coupling, composability, and fault isolation—all things we rediscovered later with actor models, microservices, and event-driven architectures.
Echoes of the Original Vision in Modern Systems
Interestingly, the message-passing paradigm never truly died—it just rebranded:
- Erlang/Elixir’s actor model thrives in telecoms and distributed systems
- Akka brought the actor model to the JVM
- Frontend frameworks (like React with Redux or Signals) emphasize event-driven state
- Microservices talk to each other via asynchronous messages
- Even JavaScript with its event loop and promises leans toward this direction
We're slowly circling back to Kay’s ideas—just under different names.
What the Future Might Hold
As systems become more distributed, concurrent, and resilient, the limitations of class-based OOP become more apparent. Message-passing models are making a comeback, particularly in:
- Cloud-native systems
- Reactive programming
- IoT
- Edge computing
With WebAssembly, actors on the edge, and decentralized systems, the need for self-contained agents that talk via messages is clearer than ever.
Finally
The original vision of OOP as message-passing between autonomous agents didn’t fail—it was simply ahead of its time. The world wasn’t ready for it in the 70s or 90s. But now, in a world of distributed apps, microservices, and real-time systems, we’re seeing that vision return—this time with the computing power, networking, and tooling to make it work.
Perhaps, in the end, message-passing didn’t lose the war—it just took a longer route to win it.
Comments ()