DRAFT – What Is an Object?
Clarifying Class, Object, Instance, and Their Real-World Meaning
Introduction
Object-oriented programming has been around for decades, yet the most basic question—what is an object?—may cause some confusion. The terms “class,” “instance,” and “object” are often tossed around casually, but they’re not synonyms. In fact, misunderstanding the distinctions can lead to sloppy modeling, unclear code, and fragile designs. In this blog entry, we’ll revisit these core concepts, ground them in analogy and practice, and set the stage for exploring design patterns like Singleton.
What is an Object?
This blog entry is a precursor to the Singleton Design Pattern (TBD). It was originally going to be part of the Singleton blog entry itself, but I decided that it has enough merits to stand on its own.
Before I dive into Singleton in the next blog, I’d like to consider Object-Oriented (OO) fundamentals and ask, “What is an object?” We use object frequently, but I’m not sure that we always use it consistently. I try my best to use it consistently, but I know that I’ve not always been consistent myself.
Sometimes we might use the term object when we mean class. Sometimes we might use the term object when we mean instance as in an instance of a class or even an object instance of a class. These two new terms suggest two more questions:
- What is a class?
- What is an instance?
What is a Class?
Code written within an OO implementation defines the behavior of a class. Our terminology is mostly consistent with OO languages since class
is a keyword for this concept in many of them. A class implementation defines relationships with other classes through inheritance, reference and delegation. Classes declare methods which define their behavior.
Classes declare and define behavior and relationships with other classes as specified within the implementation.
What is an Instance?
Classes define potential in the form of code. That potential is realized when the code is executed. Except for static
defined implementations, class potential can only be realized by an instance of a class.
An instance contains state information for a class usually in the form of the values for its private
and protected
field attributes. Multiple instances of the same class can be created, each with their own independent state.
An instance executes the methods of the class it instantiates and exhibits behaviors relative to its state information.
Classes reside in code. Instances reside in memory.
A Summary of Class, Instance and Object
Term | Definition | Key Characteristics | Example (Dog Domain) |
---|---|---|---|
Class | A blueprint or template that defines structure (fields) and behavior (methods). | - Describes what all its instances share. - No concrete data until instantiated. |
class Dog { name, age, bark() } |
Instance | A specific, occurrence of a class. Created when the program uses the class to allocate memory. | - Has actual values for fields. - Behaves according to its class definition. |
Dog d1 = new Dog("Buddy", 5) |
Object | The general term often used to refer to an instance of a class, though usage can be ambiguous. | - In many contexts, “object” = instance. - Sometimes used loosely to mean any entity in a system. |
d1 is an object of class Dog |
A few real-world examples of classes and their instances
While I consider object and instance as two terms for the same concept, I think that since we tend to focus so much upon classes when using OO, we sometimes use the term object when we really meant class. Some of our programming languages contribute to this confusion. All classes in Java inherit from a root superclass, named Object, even if it’s really a class. Experienced developers understand the intent based upon the context, but using the term object inconsistently can be confusing who are in the process of learning OO.
I will use class and instance rather than object for the rest of this blog entry to avoid any potential confusion.
Here are a few examples of classes and their instances.
Chairman Mao
Andy Warhol pioneered silk screening as an art form. His Mao prints display multiple images of Chairman Mao printed from the same silkscreen template. The silk screen template is like a class. It defines potential. Images are realized when ink is forced through the silk screen template onto paper or canvas. Here is an example of nine images of Mao created by Warhol. He was not limited to this set. He could have created many more, and I have no idea how many color combinations he assembled.
The silk-screen template was Warhol’s class, and the prints created from it were his instances.
Design Patterns
When I visualize Design Patterns, I tend to do so via classes. I have described Design Patterns throughout my blog entries using UML Class Diagrams.
Behavior defined in classes within these patterns can only be realized via instances of those classes. For many design patterns, the instance is a runtime detail that’s often assumed. This is prevalent in the Essential Design Patterns for which runtime instance realization was not addressed by the GoF. I included instance realization mostly by introducing a Configurer without much additional detail as to how it realized the instance.
There are some patterns where the instances are critical in defining behavior. This is most prevalent in the Composable Design Patterns. Composable Design Patterns define classes with relatively limited atomic behavior. No one class in a Composable Design Pattern can do everything, but an organized group of instances of the classes defined within the pattern can do anything.
The Interpreter Design Pattern is probably the greatest example of this. Each Interpreter class implements a rule in the Grammar for a Domain-Specific Language (DSL). Instances of those grammar rules are created and assembled into a parse tree by the Parser based upon a script written in the DSL. Each DSL script is parsed into its own parse tree of instances which collectively exhibits the unique behaviors defined in that DSL script. An almost infinite set of behaviors can emerge from the assembled configuration of instances created from the same set of finite rule-based classes.
Data Structures
When I visualize Data Structures, I tend to do so via object instances.
I initially struggled in my Data Structures course in college. Something wasn’t clicking. A few weeks into the semester, my professor’s lectures focuses upon specific Data Structures, such as Stacks, Queues, Deques, Lists, Trees, etc. His presentations became more visual. He drew linked list nodes. He drew the links connecting them. He updated the nodes and links in logical order, maintaining references until the list was completed for each operation. As he drew each update to the list, he wrote the code that implemented each update to the visual representation of the linked list.
While data structure code can be intimidating, just take a look at the implementation for a doubly linked list, the visual diagram of nodes and reference links made sense to me. I could see how his diagram and corresponding implementation were two representations of the same concept. It clicked.
While we didn’t have terms such as class, instance or object in 1982, my professor presented data structures graphically using the equivalent of instances, whereas the accompanying implementation was the using the equivalent of classes. I suspect that data structures are presented in academia these days as classes and instances.
I visualize data structures as instances because most data structures don’t contain too many classes. A Linked List is a ListNode class with a reference to the next ListNode. A Tree is also a TreeNode with a reference to a left sub-TreeNode and a reference to a right sub-TreeNode.
Where is the line between class and instance?
I’ve defined class as code implementing behavior and instance as the memory location for state in realizing that behavior at runtime. But it’s not always obvious what should be defined in a class and what should be realized in an instance. When should behavior reside in the class implementation, the instance state or the organization of a set of instances?
I have already illustrated an example of this decision in the previous Builder/Director blog where my initial design contained classes for Tea, Coffee, Sugar, Lemon, etc., and then as I started to test and implement my design, I realized what I had thought were different behaviors that required classes each for Tea
, Coffee
, Sugar
, Lemon
, etc. were really different state values for two classes: Drink
and AddOn
.
Domain and Modeling
The distinction between behavior residing within a class implementation or behavior residing within an instance state depends upon the domain and how the domain modeled. I’ll write about this more in the future (TBD) when I blog about Domain-Driven Design, but I can provide a summary here.
The Domain (TBD) is business concern of your customer. It’s why they exist. Their business concern could be communications, marketing, finance, health, entertainment, etc. Sometimes our customers might be external, such as creating software for a hospital or bank, and sometimes our customers might be internal, such as software we provide as employees of Google, Meta or Amazon.
The Domain Model (TBD) is how we represent the customer’s Domain and its associated behaviors within our design and implementation. There are many ways to model a Domain. Some better than others.
All models are wrong, but some are useful. ― George Box
We must decide which domain elements are important enough to model and which domain elements do not need to be included in the model.
For example, many domains include a Client
. The model for most Clients will require a name, contact information, history, etc. Clients will often be individual people, especially for domains, such as Linkedin, Meta, Amazon and Netflix.
While Clients are people, these domains won’t include height and eye color in the model. While these are attributes of people, they aren’t relevant attributes for Clients in these domains.
But what if our customer is a government agency that issues documents, such as Driver Licenses and Passports? Personal identifying features, such as height and eye color are critical to those domains, so they would be included in the Client model.
It’s a Dog-Eat-Dog World
Let’s consider two canine domains:
- Dog Shelters
- Show Dogs
Dog Shelters
Dog Shelters want to find homes for abandoned dogs. They want a website that features their furry friends with photo and a description for each dog. The description will contain basic information, such as the dog’s name, estimated age, history (if known), temperament, etc.
A shelter’s domain is relatively simple; therefor a simple model will probably suffice with a single Dog class with each individual dog being an instance of Dog.
Show Dog
A single Dog class would be woefully insufficient for Show Dog modeling needs. There may still be a Dog class, but there would be subclasses for each show group, such as: Working Group, Miniatures, etc. See: American Kennel Club. Then each show group would have subclasses for the individual breeds within those groups.
Each Group might define the characteristics of the Breeds within that Group. Each Breed might define the standards for that Breed. I don’t know enough about this domain to know whether Groups and Breeds would be their own classes or whether they could be sufficiently represented via state as was the case for Coffee, Tea and Sugar.
Regardless, each Dog instance in the show model would contain much more information than in the shelter model. The show model would contain the dog’s name, pedigree, show history, owner, trainer, and more.
The Show Dog’s domain is more complex; therefore, a more complex model will be needed to represent the Dog Groups, Breeds, and their traits.
Summary
Now that I’ve presented class and instance in excruciating detail, I can come full circle introduce the scenario that will lead to Singleton, which is where I started this blog.
In some domains or design structures, you only ever need one instance of a class—like the system clock or the configuration loader. That setup leads to the Singleton pattern (BD), which ensures single-instance behavior while addressing concerns like thread safety and testability. That’s where we’ll go next.