Designing Classes
A concrete type is the simplest kind of class.
A Second Object Begins as a Copy
When you design a class, you decide how a piece of a program will represent an idea and what that piece will be allowed to do. Not every idea needs the same amount of machinery. Some ideas are simple, and some parts of a program must run quickly. For these situations the source describes a particular kind of class called a concrete type. This article explains what a concrete type is, how to decide when it is the right choice, and why the designer must also think about what happens when an object of the class is copied.
Imagine you have written a class, and someone creates an object of that class. Then they create a second object that starts out as a copy of the first. What should that second object be? The answer is not automatic. It depends on what the class represents and on what the designer decided copying should mean. The behavior of an object when it is copied is called its copy semantics, and deciding on it is part of designing the class, not an afterthought to handle once the class is finished.
Copy semantics is the behavior of an object when it is copied, and it is a decision you make while designing a class.
The working rule is this: whenever you design a class, ask whether and how an object of that class might be copied. Many classes never need special thought here, because the default way of copying is correct for them. Others need a deliberate choice, and getting that choice wrong can produce objects that behave incorrectly after they are copied. The rest of this article follows that question from the default behavior to the cases where the default does not fit.
Tracing a Memberwise Copy
The most common default copy behavior is memberwise copy. In a memberwise copy, each member of the original object is copied to the new object. The new object is built by going through the original's members one at a time and giving each one a counterpart in the copy. The definition is short, so it helps to trace a concrete case.
Copying a simple point
A class represents a point with two members, x and y. An original object holds x = 3 and y = 4. A second object is created as a memberwise copy of the original. What does the new object contain, and how are the two objects related afterward?
- 1Identify the members of the original
The original object has two members: x, which holds 3, and y, which holds 4.
- 2Give each member a counterpart in the copy
The memberwise copy goes through the members one at a time. The new object receives its own x member and its own y member, each holding the value taken from the corresponding member of the original.
- 3Check the result
The new object now holds x = 3 and y = 4. Its members were filled from the original's members, one by one.
- 4Consider what happens next
Because each member of the new object was given its own copy of the value, changing the new object's x later does not change the original's x. For plain values like these, the two objects end up as independent objects that began with the same contents.
The new object is a member-by-member copy of the original, holding x = 3 and y = 4, and the two objects can then be changed independently.
Read the diagram from left to right. Before the copy, the original holds two members. After the copy, the original still holds its members, and the new object holds a counterpart for each one. The arrows show which member supplied each value. The new object is built from the members of the original, not from the original object as a whole.
When Concrete Types Are the Right Choice
A concrete type is the simplest kind of class.
The word simplest is the key to this definition. A concrete type is not defined by a special feature that sets it apart from other classes. Instead, it is defined by sitting at the simple end of the range of classes you could write. When you compare it with a more complicated class, the concrete type asks less of the reader and of the program. That is why the source treats it as the natural starting point when a concept is simple.
The source also gives a preference order. Where it is applicable, prefer a concrete type over more complicated classes and over plain data structures. When you shape a piece of a program, you therefore have three options to weigh: a concrete type, a more complicated class, and a plain data structure. The concrete type is the one the source asks you to prefer when it fits.
| Option | What it asks of the reader and program | When the source points toward it |
|---|---|---|
| Concrete type | The least: it is the simple end of the range of classes | Preferred where applicable, for simple concepts and performance-critical components |
| More complicated class | More: additional structure the reader must follow and the program must support | Chosen when the concept needs that added structure |
| Plain data structure | Holds data without the class-level design the concrete type provides | Considered alongside the concrete type when shaping a piece of a program |
Three options to weigh when shaping a piece of a program
Three Categories and Their Copy Behavior
The source does not present copy semantics as one rule for all classes. It sorts types into groups, and each group leads to a different conclusion about memberwise copy. The three groups are simple concrete types, sophisticated concrete types such as Vector, and abstract types. Before reading the details, compare the three groups side by side in the diagram below.
Notice the wording for each group. For simple concrete types the source says memberwise copy is often the right choice. For sophisticated concrete types such as Vector it says memberwise copy is not the right semantics. For abstract types it says memberwise copy almost never is. Read the three verdicts as a gradient: the more a type relies on more than its plain members, the less memberwise copy fits.
Why Vector Breaks Memberwise Copy
Vector is the source's running example of a type for which memberwise copy is not the right choice. Vector is a container-like type that is more sophisticated than a plain two-member object such as the point above. Before reading on, decide for yourself whether memberwise copy would be the right way to copy a Vector.
What do you think happens?
Would memberwise copy be the right way to copy a Vector?
Reveal answer
No, memberwise copy is not the right semantics for a Vector.
The source states that memberwise copy is not the right semantics for sophisticated concrete types such as Vector. A Vector is more than a plain set of values, so copying its members one by one does not give the new object the correct behavior.
The reason becomes visible when you picture a member that refers to storage holding the elements. Suppose a Vector has a member that refers to the storage where its elements live. A memberwise copy copies that member, which means the new Vector receives a reference to the same storage rather than its own storage. The diagram below shows what that produces.
In this picture, the original and the copy both point at one shared storage. If one of them changes an element, the other sees the change, even though the designer may have intended the copy to be independent. This is the failure that memberwise copy produces for sophisticated types. The member-by-member rule did exactly what it says, and that is the problem.
Copying Containers as a Separate Question
Once you accept that a type such as Vector cannot simply rely on memberwise copy, a natural follow-up question appears: how should a container be copied correctly? The source introduces this as its own topic, so it is treated separately from the general idea of copy semantics. Copy semantics tells you what copying an object should mean. Copying a container raises the further question of what happens to the elements it holds.
Containers are objects whose job is to hold other objects. Because they hold things, the copying question involves more than the container's own members. The source signals that copying containers deserves focused attention under its own heading, and the detailed rules are developed there. For this article, the important point is to recognize the question as separate, so that you do not assume the answer for a container follows automatically from the answer for a simple class.
Mistakes Designers Make with Copy Behavior
Common mistake Assuming the default copy behavior is always correct
What it looks likeA class holds a reference to storage shared with other objects, and it is copied member by member without anyone deciding what copying should mean.
Why it failsThe source says many classes never need special thought because the default is correct for them, but others need a deliberate choice. Memberwise copy is not the right semantics for sophisticated concrete types such as Vector.
Do this insteadAsk whether and how an object of the class might be copied, and make the copy semantics a deliberate decision during design.
Common mistake Choosing a concrete type without judging whether the concept is simple
What it looks likeA designer picks a concrete type for a concept that carries many rules and relationships, simply because concrete types are preferred.
Why it failsThe source's preference is conditional. It says to prefer a concrete type where it is applicable, so the concept must first be judged simple enough.
Do this insteadDecide whether the concept is simple, or whether it is a performance-critical component, before choosing a concrete type. If it is not, consider a more complicated class.
Common mistake Treating all types as members-only
Why it failsThe source sorts types into three groups with different copy verdicts. Applying the simple-type verdict to an abstract or sophisticated type gives the wrong result.
Do this insteadClassify the type first as simple concrete, sophisticated concrete, or abstract, then pick the copy semantics that suits that category.
Common mistake Assuming copying a container is the same as copying a simple object
Why it failsContainers hold other objects, so copying them is a separate question that follows from copy semantics.
Do this insteadTreat copying a container's elements as its own decision, as the source does under its own heading.
Practice: Classify and Choose
For each of the following types, decide whether it is best described as simple concrete, sophisticated concrete, or abstract, and state which copy semantics suits it. Then say whether a concrete type is the preferred option for it. Types: (1) a point with two plain numeric members; (2) a Vector that holds its elements in shared storage; (3) an abstract type that describes a family of behaviors without fixing its representation.
Hints
- The source says memberwise copy is often the right choice for simple concrete types.
- The source says memberwise copy is not the right semantics for sophisticated concrete types such as Vector.
- The source says that for abstract types memberwise copy almost never is the right semantics.
- Remember that the preference for a concrete type applies only where it is applicable, so judge whether the concept is simple first.
Key Takeaways
- A concrete type is the simplest kind of class. Where applicable, prefer it over more complicated classes and over plain data structures, especially for simple concepts and performance-critical components.
- Copy semantics is the behavior of an object when it is copied, and it is a design decision. Memberwise copy copies each member of the original object into the new object.
- Simple concrete types often suit memberwise copy, sophisticated concrete types such as Vector do not, and abstract types almost never do.
- Copying containers is a separate question that follows from copy semantics and is developed under its own heading in the source.