As a RAD Women coach, I’m often asked questions related to the intersection of classes and objects. These questions deserve a solid, concrete answer that’s long lived. But first: philosophy.

In the famous painting by René Magritte entitled “The Treachery of Images,” the following words appear below an image of a tobacco pipe: “Ceci n’est pas une pipe.” In English, this translates to: “This is not a pipe.” Philosophy circles love this image. As the title implies, it points out the ways in which the tools we use to communicate can get messy. On the one hand, this image is definitely a pipe. It’s right there, we can all see it. At the same time, this is not a pipe, but a picture of a pipe, a representation of the idea of a pipe.

Classes and objects have that same confusing duality. In this post, we’ll explore what a class is and how it’s different from an object. It’s my hope that you’ll walk away with a solid understanding of how these two concepts relate to each other.

Enter the coffee cup

To say that I love my coffee is an understatement. If I were a Care Bear, the symbol on my belly would be a cup of coffee. So, when I went looking for a metaphor to illustrate classes and objects, coffee came up. Classes and objects are abstractions, and part of what makes abstractions hard to talk about is their generic nature. So, let’s talk about a coffee cup. We’ll use our humble cup as a metaphor, enabling us to explore the duality of classes and objects.

There’s a good chance that we can all picture a coffee cup in our heads. We can list its properties: height, width, diameter, color, volume, etc. But as we list these properties, we’re talking about the idea of a coffee cup, not an actual, physical coffee cup. Critically, as we discuss the idea of a coffee cup, we can’t fill it with coffee and bring joy to our life.

For real joy, we need to progress from the idea of a thing, to an actual, physical thing. Remember the painting? We need to move from the picture of a pipe to an actual pipe. This progression is super important. We know that the idea of a coffee cup has properties like height and width. That said, we can’t know the values for those properties without an actual instance of our coffee cup. The difference between an idea and the physical manifestation of that idea mirrors the difference between a class and an object. It also nicely matches the difference illustrated by Magritte’s painting.

Classes for the win!

A class represents the idea of a thing. This is one of those deceptively simple sentences; it glosses over a ton of nuance and ignores the difficulty of discussing abstractions (like “thing”). This is why I brought in a specific “thing”: the coffee cup. In this post, we’ll discuss the Coffee Cup class, however, it’s important to understand that we use classes to model or represent any idea that we have. So, with that caveat in place, let’s talk about the idea of the humble coffee cup.

In the realm of ideas, we can identify common properties, but not concrete values. So, it’s entirely fair to say that the idea of a coffee cup has a height and a radius. After all, a coffee cup is three dimensional (a 2d version would be a picture of a coffee cup — see what I did there?). Additionally, the idea of a coffee cup has a color, but it might also have a logo. We refer to these as the properties of a class.

Note: it’s pretty easy to come up with a much longer list of properties for the idea of a coffee cup, but for simplicity’s sake, we’ll stick with these.

In Apex code, our coffee cup class might look something like this:

public with sharing class CoffeeCup {

    // effectively required properties with default values
    public Double height = 0.0;
    public Double radius = 0.0; 
    public String color = 'White';
    public Boolean hasHandle = true;
    // optional property with no default
    public Boolean hasLogo; 

}

When dealing with the idea of a coffee cup, it’s logical to note that it has a radius property. But because we’re dealing with the idea only, we don’t know what the value of that radius property could be. It’s possible — and useful — to give default values to class properties. But the default values are just that: defaults. The idea of a coffee cup can default to a radius of 1.5 inches, however, without an actual coffee cup, we don’t know if that default is valid, nor if we could change the value.

Classes also contain methods — re-usable bits of logic that manipulate the object. For instance, with our coffee cup, we might have an empty() method. Methods add an extra layer of complexity, so for this post, we’re going to ignore them. Look for a follow up post on methods in the coming weeks.

Classes are useful for modeling real-world things like a coffee cup. But until we create an instance of the class — called an object — everything about it is conceptual and read-only.

Objects are real

If a class represents the idea of a thing, an object is a concrete, real-life, instance of that class. We can manipulate and change objects; for example, instead of the idea of a coffee cup, we have my coffee cup (there are many like it, but this one is mine). Because we’ve switched from the idea to a specific coffee cup, we can now use the coffee cup.

Different programming languages use variations on the class/object terminology, so much so that developers have a tendency to use them interchangeably. This can be confusing to developers who are learning object-oriented programming (OOP), so let’s try and sort this out using concrete terminology for Apex developers.

All objects are an instance of some class.

An object must, by definition, be a specific instance of a class. This is a hard and fast rule, and a core concept in object-oriented programming: all objects are an instance of some class. Classes define even “primitive” objects like (the string) “Hello, world.” While an Apex developer may not see the source code of the string class, it’s there governing all strings.

At times, developers also refer to the type of an object, which is a different way to specify the class backing an object. If we take myCoffeeCup, we can say that it’s an instance of CoffeeCup. It’s also accurate to say that myCoffeeCup’s type is CoffeeCup. When developers ask questions like “What type of object is that?”, they’re using ”type“ as a synonym for ”class.”

One more thing: making instances of classes

In the art of programming, we model our classes on real-life objects, creating the idea of a thing like a coffee cup. Yet ideas are hard to manipulate and use. The idea of a coffee cup doesn’t get me out of bed in the morning. An instance of a coffee cup, filled with coffee, is a different story. So how do we go from the idea of a thing to an instance of a thing while coding? We use the new keyword and a special type of method called a constructor.

We all know the syntax for creating a new variable in Apex; it always looks something like this: Type variableName = new Type(). Remember, type is synonymous with class. Thus, we can also write it this way: ClassName variableName = new ClassName(). Note that this also demonstrates that all variables in Apex are, in fact, objects!

Because all variables in Apex must have a type, all variables in Apex are objects.

Looking at the code, we see that the code following the new keyword looks like a method call. Because it is. This can be confusing because there’s not always a method named className() in our code. For instance, if we look back to our class code above, there are no methods defined in that class at all. Despite the lack of a defined constructor, this works fine. Indeed, CoffeeCup myCoffeeCupHasAName = new CoffeeCup(); compiles and runs fine.

This works because every class has at least one implicit constructor. Even if you don’t code it, you can still call new ClassName(). When we call new CoffeeCup(), the compiler gives us an instance (object) of that class. This object will be blank — its properties will either be null or set to the defaults that you coded. It’s important to note that you can create custom constructors, such as one that requires an integer parameter for the amountOfCoffee in the cup. But that’s a post for another day.

Once we have an object — aka an instance of a class — we can start manipulating it. We can set and read its properties, and we can call its methods.

Conclusion

Ok, here’s the skinny: classes are ideas and objects are specific instances of a class. We use the new keyword with a constructor to create new objects, and we use objects to store properties and execute logic. What does that mean for our specific class of CoffeeCup and the instance of myCoffeeCup? Well, it means that we can define a property on the idea, or class, of CoffeeCup. It also means that we can’t modify it until we’ve created an instance of that class. We can’t fill or empty the idea of a coffee cup — those actions need an instance.

Classes and objects can seem similar, but hopefully the coffee cup example helps clarify their differences. In future posts, we’ll discuss methods, constructors, interfaces, and inheritance.

About the author

public with sharing KevinPoorman {
public static String pronouns = 'he/him';
public static Double startedWithSalesforceAtApiLevel = 11.0;
public static String[] interests = ['Apex', 'Testing', 'iOS SDK', 'Generics', 'Metaprogramming'];
public static String funFact = 'Has two daughters he\'s training to take over the world.';
public static String twitterHandle = '@Codefriar';
}

Get the latest Salesforce Developer blog posts and podcast episodes via Slack or RSS.

Add to Slack Subscribe to RSS