-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinheritance.tex
More file actions
644 lines (544 loc) · 29.6 KB
/
inheritance.tex
File metadata and controls
644 lines (544 loc) · 29.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
\chapter{Inheritance (1 of 2)}
\label{ch:inheritance}
\index{inheritance}
\index{modularity}
If one had to name object-oriented programming's most ``killer feature,'' a
good case could be made for \textbf{inheritance}. This specific technique for
code reuse and modular flexibility underlies much of the ``magic'' that happens
in well-architected OO programs, including most of the design patterns we'll
consider in later chapters. Developers need to know it, and know it well.
Interestingly, inheritance is used for two distinct (and essentially
unrelated) reasons to achieve two very different kinds of results. I call
these ``\textbf{top-down inheritance}'' and ``\textbf{bottom-up inheritance},''
for reasons I'll explain; the more standard terms are \textbf{interface
inheritance} and \textbf{implementation inheritance}, respectively.
Curiously, when I was a young'un taking object-oriented programming in
college, we learned \textit{only} about the latter of these, and I was
mystified early in my career when I saw the former in action and had no idea
what the code was doing. Only then did I realize that although bottom-up
inheritance is indeed useful, top-down inheritance is the real game changer.
We'll cover both in this chapter.
\section[\small ``Bottom-up'' (implementation) inheritance]
{\large ``Bottom-up'' (implementation) inheritance}
\index{inheritance!bottom-up (implementation)}
\index{object}
\index{class}
As you know, the Java API contains a class called \texttt{ArrayList}. The
class diagram below shows an abbreviated version of it. Already there's one
possibly unfamiliar element to you here: the literal word ``\texttt{Object}''.
It might seem odd to learn that there is a \textit{class} called
\textit{\texttt{Object}}, but that is indeed the case. And in fact this very
class will come back later in the chapter and play a major role in Java's
version of inheritance. For now, just consider that we are working with the
\textit{non}-generic \texttt{ArrayList} type -- \textit{i.e.} the user will
not declare ``\texttt{ArrayList<String>}'' but plain-ol' ``\texttt{ArrayList}''
-- so that the things that can be stored in it are ``\textit{any} type of
\texttt{Object}.'' That's why we're using the most general possible word here
as the argument of \texttt{.add()}, \texttt{.remove()}, \textit{etc.}
\begin{wrapfigure}{r}{5.5cm}
\vspace{-.2in}
\includegraphics[width=0.5\textwidth]{arrayList.pdf}
\caption{An abbreviated \texttt{ArrayList} class.}
\label{fig:abbrArrayList}
\end{wrapfigure}
\index{countUniqueArrayList@\texttt{CountUniqueArrayList}}
\index{client code}
Now suppose we were writing a program that needed to manage a bunch of
list-like data, and that \texttt{ArrayList} was just the ticket...except that
it was missing one or more important features. For example, maybe in addition
to inserting, removing, counting, \textit{etc.}, we also needed the ability to
\textit{count the number of unique elements} in a list. The client code we'd
like to be able to write is in Figure~\ref{fig:dreamCountUnique}.
\begin{figure}[ht]
\centering
\begin{Verbatim}[fontsize=\footnotesize,samepage=true,frame=single]
public static void main(String args[]) {
ArrayList n = new ArrayList();
n.add("Harry");
n.add("Ron");
n.add("Hermione");
n.add("Harry");
n.add("Harry");
n.add("Dumbledore");
System.out.println(n.get(3)); // prints "Harry"
System.out.println(n.size()); // prints 6
// *We want this to print 4, but no such method:
System.out.println(n.countUnique());
}
\end{Verbatim}
\caption{Some client code we'd \textit{like} to be able to write in our
hypothetical program.}
\label{fig:dreamCountUnique}
\end{figure}
This client code already works except for the last line, which of course
contains a method we just made up. It's sad that \texttt{ArrayList} meets all
our needs except this one teensy one.
\index{hasa association@``has-a'' association}
\index{association!has-a@``has-a''}
Several ways to get around this limitation come to mind. We could use a
\textbf{has-a} association between \texttt{ArrayList} and a new class of our
devising, ``\texttt{CountUniqueArrayList}.'' Each \texttt{CountUniqueArrayList}
would have an \texttt{ArrayList} ``under the hood'' which it would use to
actually store the data. Figure~\ref{fig:countUnique1} gives the idea.
\begin{figure}
\centering
\includegraphics[width=0.9\textwidth]{countUnique1.pdf} % 700x190
\caption{A first approach to enhancing a regular \texttt{ArrayList}.....}
\label{fig:countUnique1}
\end{figure}
\begin{figure}
\centering
\includegraphics[width=0.9\textwidth]{countUnique2.pdf} % 700x190
\caption{.....but this necessitates duplicating all the original methods.}
\label{fig:countUnique2}
\end{figure}
\index{method!pass-through}
After writing the \texttt{.countUnique()} code, the last line of
Figure~\ref{fig:dreamCountUnique} would work like a charm. Trouble is...the
other lines wouldn't work anymore. $\frownie$ \ Obviously we have to be able to
do ``normal'' \texttt{ArrayList} things with our class as well as calling our
new special method. So we'd have to duplicate all the other \texttt{ArrayList}
methods on our new class, and have them ``pass through'' the arguments to the
underlying \texttt{ArrayList} that it holds. The result is the unwieldy,
repetitive monstrosity in Figure~\ref{fig:countUnique2}, which is obviously not
a good solution. Here's what each of our ``pass-through'' methods would look
like:
\begin{Verbatim}[fontsize=\small,samepage=true,frame=single]
public class CountUniqueArrayList {
private ArrayList al;
public void add(Object o) {
al.add(o);
}
public int size() {
return al.size();
}
...etc...
}\end{Verbatim}
At the very least, this is clumsy, duplicative, and error-prone. But it could
be even worse, if the \texttt{ArrayList} class evolves. Suppose the Java API
expands to include a \texttt{.shuffle()} method on \texttt{ArrayList}, which
randomly jumbles the contents of the list? Every \texttt{ArrayList} in every
line of Java code in the world could instantly take advantage of that. But our
stunted \texttt{CountUniqueArrayList} could not: it would have to be changed
to add a \texttt{.shuffle()} pass-through method before it could do what any
other \texttt{ArrayList} could automatically do.
\label{page:inheritanceArrows}
\begin{figure}[h]
\centering
\includegraphics[width=0.7\textwidth]{inheritanceArrows.pdf}
\caption{Diagrammatic elements for inheritance. (Compare with
Figure~\ref{fig:assocArrows}, p.~\pageref{fig:assocArrows}.)}
\label{fig:inheritanceArrows}
\end{figure}
\index{isa association@``is-a'' association}
\index{association!is-a@``is-a''}
\index{triangle ($\triangle$)}
\index{line!solid (---)}
The solution is to use inheritance. \textit{Instead of ``\textbf{has-a},'' an
inheritance association means ``\textbf{is-a}.''} (See
Figure~\ref{fig:inheritanceArrows}.) Instead of each
\texttt{CountUniqueArrayList} \textit{having} an \texttt{ArrayList},
we're declaring that a \texttt{CountUniqueArrayList} in fact
\textbf{\textit{is}} an \texttt{ArrayList}. This gives it all the rights and
privileges of any \texttt{ArrayList} including all of its methods and instance
variables. All the code in Figure~\ref{fig:dreamCountUnique} \textit{instantly
just flat works}. The UML equivalent is shown in
Figure~\ref{fig:countUnique3}. Note carefully that we use an open-triangle
arrowhead to designate inheritance, and that there are no other navigability,
multiplicity, or role indicators.
\begin{figure}[h]
\centering
\includegraphics[width=1\textwidth]{countUnique3.pdf}
\caption{Bottom-up inheritance in action. (Note the open-triangle arrowhead.)}
\label{fig:countUnique3}
\end{figure}
\index{superclass}
This may seem like cheating. Surely if we want to call a method on an object,
we're entitled to see that method in the UML diagram for that object's class?
Clearly, \texttt{.add()}, \texttt{.get()}, and \texttt{.size()} do not appear
in \texttt{CountUniqueArrayList}'s box. But the magic of inheritance makes it
work anyway. The rule is that you can call a method on an object if that
method is defined on the object's class...or on any \textbf{superclass}.
\texttt{ArrayList} is said to be the ``superclass'' of
\texttt{CountUniqueArrayList}. And that brings us to a slew of equivalent
terminology.
\index{subclass}
\begin{samepage}
All of these expressions mean exactly the same thing:
\begin{center}
\small
A is-a B\\
A inherits from B\\
A specializes B\\
A is a subclass of B\\
A is a subtype of B\\
A is a derived class of B\\
B generalizes A\\
B is the superclass of A\\
B is the supertype of A\\
B is the base class of A\\
\end{center}
\end{samepage}
You know something's an important concept when there are a zillion equivalent
terms for it. And so it is with inheritance.
Sometimes we say ``A is a class, and B is its superclass.'' Other times we say
``B is a class, and A is a subclass.'' These aren't contradictory statements --
it's like saying I'm both a son (of my mom and dad) and also a father (of my
three kids). You can totally be a son and a father at the same time. And a
class can be both a superclass and a subclass.
\index{tree}
\index{inheritance hierarchy}
By the way, if you have sharp eyes, you'll have noticed I said ``or
\textit{any} superclass'' a few paragraphs ago. That's because if A inherits
from B, B can in turn inherit from some other class, which can itself inherit,
\textit{etc.} All the classes and their related sub/superclasses form what's
known as an \textbf{inheritance hierarchy}.
\subsection{Under the hood}
You might wonder how this magic works behind the scenes. It's actually pretty
simple. When we instantiate a \texttt{CountUniqueArrayList}, we not only
allocate memory for all the \texttt{CountUniqueArrayList}-specific parts (if
any), but also for its superclass parts.
\index{student@\texttt{Student}}
\index{person@\texttt{Person}}
Let's take a different example so that we know what the ``parts'' actually
are.\footnote{It may or may not surprise you that I honestly don't know what
instance variables the \texttt{java.util.ArrayList} class has, or what they're
named. This is a perfect example of the wonders of encapsulation: millions of
people across the globe use \texttt{ArrayList}s every day, and do not know or
care how they function internally!} Figure~\ref{fig:studentClass} shows two
classes in an inheritance relationship: a \texttt{Student} \textbf{is-a}
\texttt{Person}. While a \texttt{Person} in general has a \texttt{name} and
and \texttt{age}, the special type of person called a ``\texttt{Student}'' also
has an \texttt{eagleOneID} and a \texttt{gpa}.
\begin{figure}
\centering
\includegraphics[width=0.9\textwidth]{studentClass.pdf}
\caption{A \texttt{Student} is a special kind of \texttt{Person}, but a
genuine \texttt{Person} nonetheless.}
\label{fig:studentClass}
\end{figure}
\begin{samepage}
Now when we instantiate each of these classes:
\begin{Verbatim}[fontsize=\footnotesize,samepage=true,frame=single]
public static void main(String args[]) {
Person tony = new Person();
tony.setName("Tony Stark");
tony.setAge(39);
Student peter = new Student();
peter.setName("Peter Parker");
peter.setAge(17);
peter.setGPA(3.85);
peter.setEagleOneID("000518989");
}
\end{Verbatim}
\end{samepage}
the objects of each type look like Figure~\ref{fig:studentObject}. See how the
\texttt{Student} object has \textit{both} the required \texttt{Student} and
\texttt{Person} instance variables, since it is both a \texttt{Student} and a
\texttt{Person}. To Java, the fact that the \texttt{Person} ``stuff'' is in a
separate little chamber inside the \texttt{Student} box is just a detail.
\begin{figure}
\centering
\includegraphics[width=0.9\textwidth]{studentObject.pdf}
\caption{A \texttt{Student}, and an ordinary \texttt{Person}, in the heap.}
\label{fig:studentObject}
\end{figure}
The reason I call this technique ``bottom-up inheritance'' is that in order to
use the special features of your new class, \textit{you need to know you have
an instance of the subclass.} In the code above, we couldn't call
\texttt{.setGPA()} on an ordinary \texttt{Person}: it would have to be a
\texttt{Student}. We couldn't call \texttt{.countUnique()} on just any Joe
\texttt{ArrayList} -- only \texttt{CountUniqueArrayList}s have that special
method. Hence, the code that uses the classes views the hierarchy ``from the
bottom-up''; \textit{i.e.}, from the perspective of the subclass. In fact, if
all we instantiate are \texttt{Student}s (not \texttt{Person}s), then our
\texttt{main()} method doesn't even need to know there \textit{is} a
superclass. To \texttt{main()}, it's all about \texttt{Student}s, and the fact
that you can do ordinary person-ish things to a \texttt{Student} -- like set
its \texttt{age}, or ask it to \texttt{.work()} or \texttt{.sleep()} -- seem
just like other aspects of \texttt{Student}s.
The conventional term for this, ``implementation inheritance,'' comes from the
fact that the reason we're inheriting is \textit{to steal the implementation.}
Someone has already gone to the trouble of writing an \texttt{ArrayList} class
-- or a \texttt{Person} class -- and we don't want to reinvent the wheel. So
we make use of that implementation (the code in the methods) and just add
whatever else we want to the mix.
\section{``Top-down'' (interface) inheritance}
\index{inheritance!top-down (interface)}
Now top-down inheritance is where the real action is.
\index{sortedArrayList@\texttt{SortedArrayList}}
Let's go back to our \texttt{ArrayList} example, and this time I'm going to
write a different subclass, called ``\texttt{SortedArrayList}.''
Figure~\ref{fig:sortedAL} shows this arrangement. The open-triangle arrow and
the word ``is-a'' are just the same. The one thing that might strike you as
odd, though, is that the methods on the subclass are \textit{also all on the
superclass}. Hey, we already had an \texttt{.add()}, an \texttt{.insert()},
and a \texttt{.set()}: what good is our new class that just duplicates this?
As it turns out, a \textit{lot}.
\begin{figure}
\centering
\includegraphics[width=0.9\textwidth]{sortedAL.pdf}
\caption{Top-down inheritance in action.}
\label{fig:sortedAL}
\end{figure}
To explain why, first let me articulate my motive for creating the
\texttt{SortedArrayList} type in the first place. I might have a program that
needs to store various bits of data in \texttt{ArrayList}s -- a common enough
task -- but it needs some of those lists to \textit{always remain in sorted
order}. Exactly what ``in order'' means depends on the data type, but we could
expect for \texttt{Integer}s it would be numerical order, for \texttt{String}s
alphabetical order, \textit{etc.}
It's easy to imagine a program that would need this feature. Perhaps it needs
to print the various lists in some kind of reliable sequence, or to perform
fast lookup via a binary search. Anyway, the point is: if I create a
\texttt{SortedArrayList}, I'm doing so because I want a guarantee that no
matter what I do to that list, I can always get the stuff out quickly, and
sorted.
Now if you think it through, you'll realize this is a different kind of
situation than we had with \texttt{CountUniqueArrayList}. Previously, we had a
\textit{new feature} we wanted to add to an existing class -- an
\texttt{ArrayList} could do many things, but not count its number of distinct
elements, and so we tacked that feature on to the top of it. But now, we don't
want a new feature so much as \textit{different behavior for the original
features.} We don't want to add any new methods, but have \textit{the existing
methods act differently.} And thus is the essence of top-down inheritance.
\index{override}
\index{method!overridden}
Before we see it in action, let's think about the implementation. You'll
notice that in Figure~\ref{fig:sortedAL} only \textit{some} of the methods
appear in the subclass. These are called \textbf{overridden} methods: we say
that \texttt{SortedArrayList}'s \texttt{.add()} ``overrides'' the base class's
\texttt{.add()}. Now can you figure out why those particular three methods are
the ones we chose to override?
If you're sharp, you'll realize that those three methods are the only ones
which, if we called the ordinary \texttt{ArrayList} version, would threaten to
jeopardize the sorted nature of the list:
\begin{itemize}
\itemsep.1em
\item If we have a sorted list, and \texttt{.add()} an item to it, our new
expanded list might be unsorted if \texttt{.add()} just tacks the new item on
to the end. Hence, \underline{\textbf{we must override \texttt{.add()}}} with
a version that adds the new element \textit{in the correct place}.
\item If I have a sorted list, and \texttt{.remove()} an element from it, the
shorter list will still be sorted. So the superclass's \texttt{.remove()}
doesn't mess anything up, and we can stick with it. No need to add a version
to \texttt{SortedArrayList} at all.
\item Whether the list's elements are sorted or not, \texttt{.size()} acts the
same for Pete's sake, so we hardly need to override that one.
\item On the other hand, if we \texttt{.insert()} an element at a specific
location, we'll mostly likely disturb the ordered-ness, so
\underline{\textbf{we must override \texttt{.insert()}}} as well, so that it
puts the new element only where it truly belongs.
\item The \texttt{.get()} method is an easy call: retrieving element \#9 out
of a list doesn't have any different behavior if the elements are sorted or
not, so we leave that one out.
\item Lastly, though, \underline{\textbf{we must override \texttt{.set()}}}
since changing one element's value could throw the ordered-ness out of kilter,
requiring resorting.
\end{itemize}
If you followed all that, you'll realize that the choice of which methods to
override in the subclass wasn't an arbitrary one. It was dictated directly by
the behavior we wanted our subclass to guarantee and preserve. Methods whose
default implementations (in the superclass) wouldn't work for our new type (in
this case, those that threatened to jeopardize the order) must be replaced
with versions appropriate to the subclass.
The word ``override'' is a good one, and it conveys almost exactly what it
means, although don't make the mistake of thinking that the ordinary
\texttt{ArrayList}'s \texttt{.add()} method is completely obliterated by what
we've done. \textit{Au contraire}, for plain-Jane \texttt{ArrayList}s all over
the world, that original \texttt{.add()} code will still run. Only if the
object in question is one of our special subtype -- only if it's a
\texttt{SortedArrayList} in addition to being a plan \texttt{ArrayList} --
will our new method be substituted. Put another way, we're not ``overriding
the \texttt{.add()} method for \textit{everybody},'' just for objects of our
new special type.
\subsection{Test your intuition}
\begin{samepage}
Okay, now to drill the concept all the way home. I want to ask you a question.
Before reading on, consider the code below and ask yourself ``what will its
output be?'' (Commit to an answer before you continue.)
\index{Thor}
\index{Banner, Bruce}
\index{Captain America}
\index{Hulk}
\index{getMad@\texttt{.getMad()}}
\begin{Verbatim}[fontsize=\footnotesize,samepage=true,frame=single]
public static void main(String args[]) {
SortedArrayList sal = new SortedArrayList();
sal.add("Thor");
sal.add("Bruce Banner");
sal.add("Captain America");
getMad(sal);
for (int i=0; i<sal.size(); i++) {
System.out.println("Hero #" + i + " is " + sal.get(i));
}
}
private static void getMad(ArrayList al) {
al.set(0,"Hulk");
}
\end{Verbatim}
\end{samepage}
To figure this out, we first observe that the code is instantiating our
\textit{new} special kind of \texttt{ArrayList}: a \texttt{SortedArrayList}.
Therefore, we know that when \texttt{sal.add()} is called, \textit{it's our
new \texttt{.add()}} that will get executed. (Later in \texttt{main()}, we
call \texttt{sal.size()}, and this will of course trigger the ordinary
\texttt{.size()} since we didn't override that method.)
Now the big question, and the point of this exercise, is to consider what
happens \textit{inside} the \texttt{getMad()} function. Note very carefully
that \texttt{getMad()} takes an argument of type \textit{\texttt{ArrayList}},
not \texttt{SortedArrayList}. So \texttt{getMad()}, you might say, is itself
unaware that \texttt{SortedArrayList}s even exist, let alone that it's about
to be given one.
So I ask you: will \texttt{ArrayList}'s ordinary \texttt{.set()} method be
called, or will it be \texttt{SortedArrayList}'s new,
ensure-the-list-stays-sorted \texttt{.set()} that will take over?
The critical answer is: \textit{the subclass's method will be called, even
though the function itself doesn't know it's dealing with a subclass.}
\texttt{SortedArrayList.set()} will be called in this case, which will swap
\texttt{Hulk} with \texttt{Captain America} to keep the list alphabetically
sorted, giving this output:
\begin{Verbatim}[fontsize=\small,samepage=true,frame=single]
Hero #0 is Captain America
Hero #1 is Hulk
Hero #2 is Thor
\end{Verbatim}
This surprises lots and lots of folks. It certainly surprised me when I
learned it (considerably after graduating college). I originally reasoned as
follows: ``\texttt{getMad()} was written to take an ordinary
\texttt{ArrayList}, and hence its code was designed with only
\texttt{ArrayList}s in mind. Surely this means that our three-hero-list, when
\texttt{getMad()} receives it, will be treated just as any normal
\texttt{ArrayList} would be. All that special overriding method stuff only
happens when we \textit{know} we're dealing with a \texttt{SortedArrayList} in
particular.''
The exact opposite is true. And it turns out that's how we want it to be.
Consider this very example: what good is a \texttt{SortedArrayList} if it
doesn't stay sorted? That was the whole point of the subclass! Yet we'd be
threatening to violate this very principle if we ever passed it into contexts
which didn't know it needed to be sorted, and hence unwittingly jumbled it up.
We must guarantee that \textit{every time} \texttt{.add()},
\texttt{.insert()}, or \texttt{.set()} is called on it, our new functionality
is triggered, whether or not the user of the object even knew that.
\subsection{``Masquerading'' and ``smuggling''}
\index{inheritance!top-down (interface)}
Now why do I call this ``top-down inheritance?'' The reason is that unlike with
bottom-up inheritance, you can use objects of your new subclass
\textit{without knowing they're of that subclass, or that there even is a
subclass.} As a user of the classes -- like \texttt{main()}, above -- you're
looking at the inheritance hierarchy from the top down.
\index{masquerading@``masquerading''}
\index{smuggling@``smuggling''}
A couple of other descriptive words I like to use for this are ``masquerading''
and ``smuggling.'' Here, the \texttt{SortedArrayList} \texttt{sal} is
masquerading as an \texttt{ArrayList} -- pretending to be one for the sake of
the \texttt{getMad()} function. (And of course it's not actually ``pretending''
because a \texttt{SortedArrayList} truly \mbox{\textbf{is-a}}
\texttt{ArrayList}.) From \texttt{main()}'s point of view, we smuggled a
\texttt{SortedArrayList} into the \texttt{getMad()} function, in cognito.
Little did \texttt{getMad()} know that it wasn't even dealing with an ordinary
object of the base class. It was fooled by the disguise.
\subsection{Why this matters}
\index{decoupling}
The reason this idea is so powerful is that it allows programmers to decouple
the \textit{what} from the \textit{how}.
A chunk of code that only knows about the superclass (in our example,
\texttt{ArrayList}) can dictate \textit{what} to do with it. ``First I'll
\texttt{.add()} these three elements, then I'll \texttt{.remove()} one, then
get the \texttt{.size()}, \textit{etc.}''
In response to these method calls, the object itself -- perhaps of a
specialized subclass -- decides \textit{how} to carry out each one. An
ordinary \texttt{ArrayList} tacks the new element onto the end when it's told
to \texttt{.add()} one, whereas a \texttt{SortedArrayList} decides to stick it
in the appropriate place to preserve the order. The original code chunk can be
blissfully ignorant of how the details of \texttt{.add()}, \texttt{.insert()},
\textit{etc.}~work for any particular type of \texttt{ArrayList}.
\index{Super Smash Bros}
\index{Zelda}
\index{Peach}
If you're a videogamer, think of it in Smash Bros.~terms. Every character in
the game looks different, has different attack stats, different animations for
punching and falling, a different ``up smash'' and ``side special,'' and so
forth. But the main game engine code that coordinates the interaction between
characters on a stage doesn't have to worry about all those details. It can
simply say, ``hey, P1 (character \#1), your player just input a dash-left.
Display the appropriate animation please.'' The object for P1, who may happen
to be Zelda, then displays her determinedly zooming to the left with her hair
flowing behind her.
The game then says, ``hey, P4, you just got punched. First, tell me your weight
class so I know how far the knockback should be.'' If character \#4 is Peach,
her object responds, ``I'm in the medium weight class.'' The game then says,
``thanks. Now display your `hit stun' animation from your current position up
to coordinates 562, 431.'' The Peach object then shows her character flying
through the air with her umbrella in a tizzy.
\index{separation of concerns}
For even moderately complex programs, this ability to compartmentalize these
two jobs is crucial -- otherwise you end up with a 500-line function that's a
mass of spaghetti code. Software engineers call this decoupling
``\textbf{separation of concerns},'' and it is among the most important
principles in all of software development.
\section{``Cool! Can we do both?''}
A common question at this point is whether top-down and bottom-up inheritance
can be combined in a single class. The answer is yes! If you create a
subclass \texttt{A} of another class \texttt{B}, you could have some methods
of \texttt{A} override the existing methods of \texttt{B}, and you could also
have some brand new methods in \texttt{A} that weren't present in \texttt{B}.
Any code that deals with \texttt{B} objects will automatically work for
\texttt{A} objects also, and your new method implementations will be called
when it does. And you can write code that calls your brand new methods, as
long as that code \textit{knows it's dealing with an \texttt{A}}.
It's not super common to combine the techniques, but I've seen it done.
\section{A word of warning}
I'll finish this chapter with an observation from my years coding. Inheritance
tends to be both an \textit{underused} feature and an \textit{overused}
feature.
What I mean is that programmers (even experienced ones, sadly) sometimes fail
to recognize situations in which inheritance would be appropriate, and their
code becomes less elegant and more brittle as a result. Even more worrying,
I've seen more than one ``inheritance-happy'' programmer in my career use it
where it's \textit{not} called for. And this turns out to be even worse.
Although there are shades of grey, the basic rule for knowing when inheritance
is appropriate can actually be boiled down to a single principle:
\index{isa association@``is-a'' association}
\index{association!is-a@``is-a''}
\begin{center}
{\large \HandRight} \ \textbf{Remember that ``is-a'' means ``is-a.''} \ {\large \HandLeft}
\end{center}
\index{subclass}
The time \textit{not} to use inheritance is when you see some code that you
want to reuse, but you really \textit{don't} have a conceptual ``subtype'' in
mind.
\index{runner@\texttt{Runner}}
\index{performance@\texttt{Performance}}
\index{race@\texttt{Race}}
An actual example: suppose your team is building a database system for 5k and
10k race results. There's a \texttt{Runner} class with inst vars like
\texttt{name} and \texttt{gender} and \texttt{dateOfBirth}. Then you say,
``all right: to record a performance in a particular race, we need all that
information about the runner, \textit{plus} the bib number, finish time, date
and location of the race.''
You may be tempted (as a colleague of mine once was) to create a
\texttt{Performance} class which \textit{inherits} from \texttt{Runner}. After
all, every \texttt{Performance} object would then possess all the necessary
attributes -- those of the racer, and those of the race. What's not to like?
Well, there are two problems. One is conceptual: could one possibly claim that
a \texttt{Performance} \textbf{is-a} \texttt{Runner}?! Obviously not. The very
fact that you could call \texttt{.getGender()} on a \texttt{Performance}
object, or pass a \texttt{Performance} to a \texttt{Race.register()}
method defies logic.
The other problem is practical: as these two nonsensically-joined classes
evolve, more pressure builds in the system that exposes the design flaw. When
a data entry mistake is corrected, for example, changing a \texttt{Runner}'s
name from \texttt{"Stanly"} to \texttt{"Stanley"}, only one of Stanley's
performances will have its \texttt{name} corrected; the other independent
copies for his other performances remain out of date. Even worse, suppose the
need arises for different (legitimate) subtypes of \texttt{Runner}:
\texttt{AmateurRunner} and \texttt{CompetitiveRunner}, say. Now
the \texttt{Performance} class is really in a bind: it only inherits from the
more general type, and would have to proliferate itself awkwardly
(``\texttt{AmateurPerformance}'' and ``\texttt{CompetitivePerformance}'') just
to stay in sync.
The lesson here is that your object-oriented model should strive to faithfully
reflect conceptual reality; it should not use design features in gimmicky ways
to achieve short-term programming wins. Always ask yourself ``does this choice
of classes really make \textit{sense}?'' as your guiding question.