Skip to main content
HistoryComputing historyBeginner

Object-oriented programming: objects, messages, and reusable abstractions

From Simula and Smalltalk to modern classes and prototypes, understand objects, messages, encapsulation, polymorphism, and the limits of inheritance.

Published 10 August 2026Updated 15 September 2026Reading : 8 minBy Yann Bastien
Object-oriented programming represented through objects, messages, and reusable abstractions
Show contents
  1. Before objects: procedures, data, and growing complexity
  2. Simula: representing actors in a simulation
  3. Class and object: different concepts
  4. Alan Kay and another vision of objects
  5. Smalltalk: everything becomes an object
  6. Objects as state, identity, and behavior
  7. Encapsulation and abstraction
  8. Inheritance: useful, not universal
  9. Polymorphism: different objects, one contract
  10. C++: objects meet systems programming
  11. Objective-C: message passing on top of C
  12. The 1990s: object orientation becomes mainstream
  13. Java, C#, and industrial adoption
  14. Python and JavaScript: other object models
  15. Composition over inheritance
  16. Interfaces, SOLID, and design principles
  17. Patterns, UML, and design tools
  18. Testing, dependencies, and abstraction limits
  19. Criticism of object-oriented programming
  20. Objects and other paradigms
  21. GUIs, games, and distributed systems
  22. What really remains of OOP?
  23. Why still learn object-oriented programming?
  24. Key takeaways
  25. Frequently asked questions
  26. What is object-oriented programming?
  27. Who invented object-oriented programming?
  28. What is the difference between a class and an object?
  29. What are the main principles of OOP?
  30. Is inheritance required?
  31. Is JavaScript object-oriented?
  32. Is Python object-oriented?
  33. Is object-oriented programming obsolete?
  34. Should composition be preferred over inheritance?
  35. Why does OOP still matter?

Object-oriented programming, usually abbreviated OOP, is so familiar today that it is easy to forget it emerged from a specific historical evolution in software design. Classes, objects, methods, inheritance, interfaces, and polymorphism are everyday vocabulary, yet these ideas did not appear together or as a universal recipe.

Object orientation grew from a practical question: how can a program represent entities that have state, behavior, and interactions with other entities?

From Simula to Smalltalk, and later C++, Java, Python, and JavaScript, the answer changed considerably. OOP is best understood as a family of ideas: keeping data close to behavior, hiding details, sending messages, substituting objects behind common contracts, and building reusable abstractions.

Before objects: procedures, data, and growing complexity

High-level languages of the 1950s and 1960s brought functions, procedures, data structures, and modules. As systems grew, however, data representing one entity could be manipulated by functions scattered throughout a program. Changing its internal representation became costly. Simulation produced one of the most influential answers.

Simula: representing actors in a simulation

During the 1960s, Norwegian computer scientists Ole-Johan Dahl and Kristen Nygaard worked on simulation languages. With Simula 67, they introduced mechanisms later recognized as foundational: classes, objects, inheritance, and virtual methods. A class describes a category of entities; an object represents one particular instance.

Programs could now be organized around actors in a domain rather than only sequences of procedures.

Class and object: different concepts

In the classical model, a class defines common structure and behavior. An object is a concrete instance created from it. A Car class might define speed, fuel, and operations such as accelerating or braking. Two cars share the same organization but retain separate state.

This distinction became central to C++, Java, and C#, but it is not universal. Prototype-based systems work differently, and some languages treat classes themselves as objects.

Alan Kay and another vision of objects

In the late 1960s and early 1970s, Alan Kay developed another vision, explored further in our biography of Alan Kay. For Kay, the essential idea was not primarily classes or inheritance but autonomous objects exchanging messages. Each object protects its internal state and decides how to respond.

Smalltalk: everything becomes an object

At Xerox PARC, Alan Kay, Dan Ingalls, Adele Goldberg, and others developed Smalltalk. Numbers, collections, and classes participate in the object model, and interaction centers on message sending. Smalltalk also provided a complete interactive environment where programs could be explored and modified, influencing personal computing and IDEs.

Objects as state, identity, and behavior

An object commonly combines state, behavior, and identity. Two bank accounts can have the same balance without being the same account. Identity is useful in some domains; elsewhere immutable values and functions may be preferable. OOP is therefore a powerful model for certain problems, not a universal requirement.

Encapsulation and abstraction

Encapsulation groups state with the operations that manipulate it and limits access to internal details. Its goal is to reduce dependencies and allow an abstraction to evolve internally without breaking users.

Abstraction exposes what a component can do without requiring knowledge of its implementation. A File object can offer read, write, and close operations without exposing underlying system calls. OOP did not invent abstraction, but popularized a form centered on entities combining state and behavior.

Inheritance: useful, not universal

Inheritance lets one class acquire and specialize characteristics of another. It can factor code but also strongly couples base and derived classes. Deep hierarchies may become rigid and risky to change. Experience therefore turned inheritance into one tool among many rather than the automatic mechanism for reuse.

Polymorphism: different objects, one contract

Polymorphism lets the same code work with different object types as long as they provide expected behavior. Depending on the language, it may use inheritance, interfaces, protocols, duck typing, or generics. The deeper idea is to program against a contract rather than one exact implementation. Virtual methods and dynamic dispatch are one way to achieve this at runtime.

C++: objects meet systems programming

Beginning in 1979, Bjarne Stroustrup sought to combine Simula-inspired abstractions with C’s efficiency. The project became C++. C++ spread classes, constructors, destructors, inheritance, and virtual functions throughout industry while retaining procedural and generic programming.

Objective-C: message passing on top of C

Created in the early 1980s by Brad Cox and Tom Love, Objective-C combined C with a dynamic model inspired by Smalltalk. It became important at NeXT and later Apple before Swift. C++ and Objective-C thus illustrate different interpretations of object orientation: compiled abstractions and resource control versus dynamic message sending.

The 1990s: object orientation becomes mainstream

During the 1990s, OOP became a dominant model. Graphical interfaces suited it well, while object-oriented analysis, design patterns, and UML spread through industry. OOP was sometimes presented as a general way to design every system, producing both lasting practices and excesses.

Java, C#, and industrial adoption

Java arrived in 1995 with classes at the center of its historical model, automatic memory management, and interfaces instead of multiple class inheritance. Our history of Java and biography of James Gosling cover that evolution.

C# later adopted many familiar Java and C++ ideas in .NET before adding generics, lambdas, LINQ, records, and pattern matching. This multiparadigm evolution shows that even strongly object-associated languages no longer treat OOP as the only abstraction.

Python and JavaScript: other object models

Python supports classes, inheritance, and polymorphism without requiring classes everywhere. Functions are values, and duck typing often emphasizes behavior rather than a precise hierarchy.

JavaScript, created by Brendan Eich, historically relies on prototypes. Modern class syntax still operates over that mechanism. Both languages remind us that object orientation is not synonymous with classical class hierarchies.

Composition over inheritance

With experience, favor composition over inheritance became widespread advice. Composition often reduces coupling and makes components easier to replace. It does not make inheritance useless; it shows that reuse does not always require a class tree.

Interfaces, SOLID, and design principles

Interfaces separate what a component needs from the exact implementation satisfying it. This idea underlies dependency injection and several SOLID principles: single responsibility, open/closed, Liskov substitution, interface segregation, and dependency inversion.

These principles are influential heuristics, not laws. Applying them mechanically can multiply classes, interfaces, and layers without benefit. An abstraction is useful when it represents a real boundary of responsibility or variation.

Patterns, UML, and design tools

In 1994, Design Patterns: Elements of Reusable Object-Oriented Software popularized patterns such as Factory, Observer, Strategy, Decorator, and Adapter. Their main value is shared vocabulary, not recipes to apply everywhere.

At roughly the same time, UML unified several modeling methods. Class diagrams became strongly associated with object design. Patterns and diagrams are reasoning tools; neither replaces design suited to the actual problem.

Testing, dependencies, and abstraction limits

Encapsulation, interfaces, and dependency injection can improve testability by allowing dependencies to be replaced with fakes, stubs, or mocks. But fragmenting an architecture solely to make mocking easier can have the opposite effect. More abstractions do not automatically mean better design.

Criticism of object-oriented programming

As OOP became dominant, its limits became clearer: fragile deep hierarchies, shared mutable state, highly interconnected objects, premature abstractions, and “enterprise” architectures overloaded with layers and factories.

These criticisms do not make objects obsolete. They show that a widely adopted paradigm eventually gets applied to problems for which it is not always the best fit.

Objects and other paradigms

Functional programming emphasizes pure functions and immutable data. Modern Java, C#, C++, Python, and JavaScript combine object-oriented ideas with functional ones. The opposition between “object-oriented” and “functional” is therefore less useful today.

A complex domain may benefit from rich objects protecting invariants, while a data transformation pipeline may be clearer with simple structures and composable functions.

GUIs, games, and distributed systems

Graphical interfaces and games remain domains where state, identity, and behavior naturally fit objects. Yet game engines also use Entity Component System (ECS) models favoring composition over deep inheritance.

In distributed systems, the actor model organizes computation around entities receiving messages and maintaining state. An actor is not a Java or C++ object, but the model echoes Alan Kay’s emphasis on messages and isolation.

What really remains of OOP?

After decades of experience, encapsulation, polymorphism, composition, and identity and state where needed remain especially durable. The idea that good architecture must form a large class hierarchy has lost much of its influence.

Smalltalk, C++, Java, Python, and JavaScript differ enough to show that OOP is better understood as a family of programming models than an absolute checklist.

Why still learn object-oriented programming?

A vast amount of existing software and frameworks relies on classes and objects. Encapsulation, responsibility, interfaces, and polymorphism also extend beyond strictly object-oriented languages. Maturity is less about “using objects everywhere” than choosing the right representation for the problem.

Key takeaways

OOP emerged in the 1960s with Simula, then Smalltalk and Alan Kay developed a message-centered vision. C++ brought object abstractions into industrial programming, and Java helped make them mainstream in the 1990s. Python and JavaScript demonstrated more dynamic and multiparadigm approaches.

Experience corrected several excesses: inheritance is no longer the natural answer to every reuse problem, while composition, interfaces, immutability, and functions play larger roles.

The durable lesson is not “everything must be a class,” but rather: group coherent responsibilities, hide unnecessary details, and let components collaborate without depending excessively on one another’s internal implementation.

Frequently asked questions

What is object-oriented programming?

It is a family of approaches organizing software around objects with state, identity, and behavior that collaborate through methods, messages, or interfaces.

Who invented object-oriented programming?

There is no single inventor. Ole-Johan Dahl and Kristen Nygaard introduced foundational mechanisms in Simula; Alan Kay and the Smalltalk team later developed a message-centered vision.

What is the difference between a class and an object?

A class generally describes common structure and behavior. An object is a particular instance with its own state. Prototype-based systems differ.

What are the main principles of OOP?

Encapsulation, abstraction, inheritance, and polymorphism are commonly cited. Modern practice also emphasizes composition, interfaces, and dependency management.

Is inheritance required?

No. Many object-oriented systems favor composition or interfaces.

Is JavaScript object-oriented?

Yes, but its historical model is prototype-based. Modern class syntax still relies on prototypes underneath.

Is Python object-oriented?

Python strongly supports OOP, but it is multiparadigm and does not require all code to be organized into classes.

Is object-oriented programming obsolete?

No. It remains widely used, but is no longer treated as a universal solution.

Should composition be preferred over inheritance?

Often, composition produces more flexible and less coupled components. Inheritance remains useful for genuine specialization with a stable base contract.

Why does OOP still matter?

Because encapsulation, responsibilities, contracts, and polymorphism remain useful for managing complexity even in multiparadigm architectures.

Was this article useful?

Sources and references

Collection

Programming languages

10 / 26

  1. 01Grace Hopper: from early compilers to COBOL
  2. 02John Backus: FORTRAN, BNF, and the rejection of machine code
  3. 03Dennis Ritchie: the C language at the heart of Unix
  4. 04FORTRAN: proving that a compiler could compete with assembly
  5. 05The C language: making systems portable without hiding the machine
  6. 06Niklaus Wirth: from Pascal to Oberon, designing through simplicity
  7. 07Bjarne Stroustrup: designing C++ without giving up performance
  8. 08Pascal: learning to program by making structure visible
  9. 09C++: from C with Classes to modern C++
  10. 10Object-oriented programming: objects, messages, and reusable abstractions
  11. 11Guido van Rossum: creating Python to make code readable
  12. 12Brendan Eich: JavaScript, from Netscape prototype to Web standard
  13. 13James Gosling: the engineer behind Java
  14. 14Python: readability, batteries included, and a global ecosystem
  15. 15Java: write once, run anywhere
  16. 16JavaScript: the language that made the Web interactive
  17. 17Ken Thompson: from Unix to Go, simplicity as a method
  18. 18John McCarthy: Lisp and the idea of programming with symbols
  19. 19Alan Kay: Smalltalk and the computer as a personal medium
  20. 20Barbara Liskov: the abstraction that made software modular
  21. 21Robin Milner: ML, machine-assisted proof, and languages of interaction
  22. 22Brian Kernighan: AWK, Unix, and the art of explaining code
  23. 23Anders Hejlsberg: from Turbo Pascal to C# and TypeScript
  24. 24Larry Wall: Perl, the language that connected the tools of the Internet
  25. 25Yukihiro Matsumoto: Ruby and programmer happiness
  26. 26Rasmus Lerdorf: PHP and the democratization of the dynamic Web
BiographyComputing historyBeginner

James Gosling: the engineer behind Java

How James Gosling and Sun's Green team designed Java: from Oak and virtual machines to portability and the language's lasting legacy.

17 August 20266 min