1.10 Objects and classes
Let’s return to cooking. I recently ran out of bay leaves in our kitchen. Bay leaves are used to flavor many foods, most notably soups, stews, and other braised meat dishes. Okay, I thought, I’ll just order some bay leaves online. I found four varieties:
- Turkish or Mediterranean bay leaves, from the Bay Laurel tree,
- Indian bay leaves,
- California bay leaves, and
- Caribbean bay leaves.
I eventually discovered that what I wanted was Turkish bay leaves. I ordered six ounces. When they arrived, I realized that I had enough to last the rest of my life.
Let’s get back to the varieties. While numbers and strings are built into most programming languages, bay leaves most certainly are not. Nevertheless, I want to create a structure to represent bay leaves in a first-class way. Perhaps I’m building up a collection of ingredient objects to use in digital recipes.
Before we consider bay leaves in particular, let’s think about leaves in general. Without
worrying about syntax, we define a class called Leaf
. It has two
properties: is_edible
and latin_name
.
Once I create a Leaf
object, you can ask if it is edible and
what its Latin name is. Depending on the programming language, you can either examine the
property directly or use a function on an object of class Leaf
to get the information.
A function that operates on an object of a class is called a method.
For most users of the class, it is best to call a method to get object information. I do not
want to publish to the world how I store and manipulate that data for objects. If I do this, I,
as the class designer, am free to change the internal workings. For example, maybe I initially
store the Latin names as strings, but I later decide to use a database. If a user of
Leaf
assumed I always had a string present, their code would
break when I changed to using the database.
This hiding of the internal workings of classes is called encapsulation.
Now we define a class called BayLeaf
, and we make it a
child class of Leaf
. Every BayLeaf
object is also a Leaf
. All the
methods and properties of Leaf
are also those of BayLeaf
. Leaf
is the parent class of
BayLeaf
.
Moreover, I can redefine the methods in BayLeaf
that I
inherit from Leaf
to make them correct or more specific. For
example, by default, I might define Leaf
so that an object of
that type always returns false when asked if it is edible. I override that method
in BayLeaf
so that it returns true.
I can add new properties and methods to child classes as well. Perhaps I need methods that
list culinary uses, taste, and calories per serving. These are appropriate to objects of
BayLeaf
because they are edible, but not to all objects in class
Leaf
. Every object that is a bay leaf should be able to provide
this information.
Continuing in this way, I define four child classes of BayLeaf
: TurkishBayLeaf
, IndianBayLeaf
, CaliforniaBayLeaf
, and
CaribbeanBayLeaf
. These can provide specific information about
taste, say, and this can vary among the varieties.
In many languages, a class can have at most one parent. In some, multiple inheritance is allowed, but the languages provide special rules for properties and methods. That’s especially important when there are name collisions; two methods from different parents may have the same name but different behavior. Which method is called? For an analogy, consider the rules of genetics that determine the eye color of a child.
If we define the Herb
class, then we can draw this class
hierarchy. The arrows point from the class parents to their children.
Exercise 1.11
My brother likes bay rum cologne, which is made from Caribbean bay leaf. In which classes would you place a method that tells you whether you can make cologne from a variety of bay leaf? Where would you put the default definition? Where would you override it?
In this example involving bay leaves, the methods returned information. If I create a class for polynomials that all use the same variable, then I would likely define methods for addition, subtraction, negation, multiplication, quotient and remainder, degree, leading coefficient, and so forth.
In this section, I discussed what we call object-oriented programming (OOP) as it is implemented in languages like Python, C++, Java, and Swift. The terms superclass and subclass often replace parent class and child class, respectively. Once you are familiar with Python’s style of OOP, I encourage you to look at alternative approaches, such as how JavaScript does it.