HN Debrief

Alan Kay on the meaning of "object-oriented programming" (2003)

  • Programming
  • Software Architecture
  • History
  • Developer Tools

The post is Alan Kay’s old answer to the question of what object-oriented programming was supposed to mean. His definition is narrow and sharp: messaging, local state that is hidden and protected, and extreme late binding. That clashes with the version most developers inherited from Java, C++, and the design-pattern era, where classes, inheritance, and type hierarchies became the center of gravity. Most of the useful discussion landed on that mismatch. People were not really debating Kay’s quote so much as pointing out that modern “OOP” is a bundle of ideas from different lineages that got collapsed into one name.

If you are using “OOP” to justify an architecture choice, define which properties you actually want: encapsulation, dynamic dispatch, messaging, isolation, or modularity. Treat the term itself as too overloaded to guide design decisions or team discussions.

Discussion mood

Mostly skeptical of mainstream OOP and sympathetic to Kay’s original framing. The frustration was aimed less at objects themselves and more at how Java and C++ turned OOP into classes, inheritance, and pattern-heavy ceremony while still failing to deliver loose coupling or clear architecture.

Key insights

  1. 01

    The history is messier than Simula vs Smalltalk

    The usual story draws a clean line between Simula as “classes and inheritance” and Smalltalk as “message passing.” These comments argue that reality is more tangled. Simula already had active process ideas that look a lot like message-driven objects, and later Smalltalk implementations behaved much more like Simula-style virtual dispatch than the mythic version of pure messaging suggests. That undercuts the easy habit of mapping today’s language camps onto a simple founding split.

    Do not lean on a cartoon history when you explain your architecture. If lineage matters for your team, separate surface philosophy from actual runtime semantics.

      Attribution:
    • Rochus #1 #2 #3
  2. 02

    Loose coupling usually comes from structure outside OOP

    The sharpest critique was that objects do not naturally create loose coupling. By default, objects can construct each other and call each other directly, which bakes in knowledge of concrete peers. The comments point to ports-based modeling tools like Modelica, Simulink, and Simcenter Amesim as examples of a stricter architecture where components only interact through declared inputs and outputs, and wiring happens at a higher level. That kind of boundary discipline can be recreated in object-oriented code, but it is not what the paradigm gives you for free.

    If loose coupling is the goal, encode it explicitly with boundaries, ports, and composition rules. Do not assume classes and interfaces will produce it on their own.

      Attribution:
    • sirwhinesalot #1 #2 #3 #4
  3. 03

    Kay-style objects rhyme with microservices

    Several comments made the connection that Kay’s emphasis on message passing, local state, and isolation sounds closer to microservices than to in-process class hierarchies. The useful twist is that this is about interaction style, not deployment topology. One commenter pushed “in-process REST” as an attempt to keep the communication model while dropping process boundaries. That reframes Kay OOP as a service-like design discipline rather than a language feature checklist.

    When people invoke Kay’s OOP, ask whether they really mean service boundaries and message protocols. That may point you toward API design and failure handling, not toward classes or inheritance.

      Attribution:
    • _pdp_ #1
    • mpweiher #1 #2
    • TZubiri #1
  4. 04

    Objects as computations stretched over time

    A more philosophical but surprisingly concrete framing described an object as a computation that preserves its working state across a sequence of external events. In that view, a function consumes the whole event sequence in one shot, while an object is the same kind of computation suspended and resumed message by message. That makes objects, closures, coroutines, and state machines feel like neighboring tools for the same underlying job. It is a better mental model than “bundle of data and methods” because it explains why objects show up naturally in user interfaces, simulations, and reactive systems.

    Use this model when deciding between functions, objects, actors, and coroutines. The key question is whether your logic must survive and evolve across externally driven events.

      Attribution:
    • Mikhail_Edoshin #1 #2

Against the grain

  1. 01

    Paradigm wars miss the real engineering tradeoff

    This pushes back on the whole search for the one true meaning of OOP. The more useful truth is that object-oriented, functional, and procedural styles all collapse into a mess when stretched past the point where they fit the problem. Architecture is hard because requirements move, and the indirection you add for future flexibility costs real cognitive overhead right now. That shifts the discussion from ideological purity to timing and scale.

    Pick the smallest abstraction that fits the current problem and expect to revise it. Over-optimizing for future extensibility is often the first architecture mistake.

      Attribution:
    • titzer #1
  2. 02

    An object can be just data plus behavior

    While many comments chased Kay’s message-passing ideal, this line argues for a much simpler definition. An object is data together with code that manipulates it. Privacy and deep messaging semantics are optional details, not the essence. That matters because it explains why many working programmers hear these debates as overreach. Their day-to-day use of objects is narrower and still useful.

    If you are teaching or documenting a codebase, match the definition to the job at hand. A maximalist historical definition can confuse teams that only need ordinary encapsulated state and behavior.

      Attribution:
    • usrnm #1 #2
    • sirwhinesalot #1

In plain english

dependency injection
A technique where objects receive the services they need from outside instead of constructing them directly.
Entity Component System
An architecture, common in game development, that separates data into components and behavior into systems operating over that data.
late binding
Deferring the choice of which code to run until runtime rather than fixing it earlier at compile time.
Modelica
A modeling language used to describe physical and engineered systems as connected components.
OOP
Object-oriented programming, a style of programming built around objects that combine state and behavior.
REST
Representational State Transfer, a common style for designing web APIs around resources and standard HTTP methods.
Simcenter Amesim
A Siemens tool for modeling and simulating mechatronic and physical systems using components and ports.
Simula
An early programming language, originally built for simulation, that introduced classes and inheritance.
Simulink
A MathWorks graphical environment for modeling and simulating dynamic systems with connected blocks.
Smalltalk
An influential programming language and environment that shaped many ideas associated with object-oriented programming.
virtual dispatch
A runtime mechanism that selects which method implementation to call based on an object's actual type.

Reference links

History and definitions of OOP

People and writing on programming history

  • Tomas Petricek
    Recommended for work on the history and philosophy of programming.

Talks and essays critiquing OOP

Microservices and in-process messaging

Object models and delegation

Language history and influence