Uploaded by yifan shi

A Little Java, A Few Patterns ( Matthias Felleisen, Daniel P. Friedman, Ralph E. Johnson )

advertisement
A Little J ava, A Few Patterns
Copyighted Material
A Little Java, A Few Patterns
Matthias Felleisen
Rice University
Houston, Texas
Daniel P. Friedman
Indiana University
Bloomington, Indiana
Drawings by Duane Bibby
Foreword by Ralph E. Johnson
The MIT Press
Cambridge, Mssachusetts
London, England
Copighted Mateial
Second printing. 2000
© 1998 Mssachusetts Institute of Technology
All rights reserved. No part of this book may be reproduced in any form by any
electronic or mechanical means (including photocopying. recording, or information
storage and retrieval) without permission in writing rom the publisher.
T his book was set by the authors and ws printed and bound in the United States
of America.
Library of Congress Cataloging-in-Publication Data
Felleisen, Matthis
A little Java, a few patterns. / Matthis Felleisen and Daniel P. riedman;
drawings by Duane Bibby; foreword by Ralph E. Johnson
p. cm.
Includes index and bibliographical references.
ISBN 0-262-56115-8 (pbk : alk. paper)
1. Java (Computer program language) I. riedman, Daniel P. II. Title.
QA 76. 73.J38F45
1998
005.13'3-dc21
97-40548
CIP
Copyrighted Material
To Helga, Christopher, and Sebastian.
To Mary, Rob, Rachel, Saa,
and to the memory of Brian.
Copighted Mateial
Contents
Foreword ix
Preface xi
Experimenting with Java xiii
1. Modern Toys 3
2. Methods to Our Madness 13
3. What's New? 43
4. Come to Our Carousel 57
5. Objects Are People, Too 69
6. Boring Protocols 85
7. Oh My! 99
8. Like Father, Like Son 117
9. Be a Good Visitor 139
10. The State of Things to Come 161
Commencement 177
Index 178
Copighted Mateial
FOREWORD
Learning to program is more than learning the syntactic and semantic rules of a programming
language. It also requires learning how to design programs. Any good book on programming
must therefore teach program design.
Like any other form of design, program design hs competing schools.
These schools are
oten ssociated with a particular set of languages. Since Java is an object-oriented programming
language, people teaching Java should emphsize object-oriented design.
Felleisen and riedman show that the functional
( input-output
driven ) method of program
design naturally leads to the use of well-known object-oriented design patterns.
In fact, they
integrate the two styles seamlessly and show how well they work together. Their book proves that
the functional design method does not clsh with, but supports object-oriented programming.
Their success doesn't surprise me, because I've seen it in Smalltalk for many years, though
unfortunately, it seems to have remained one of the secrets of object-oriented design.
I
am
happy to see that Felleisen and riedman have inally exposed it. This book will be especially
useful if you are a C++ programmer learning Java, since you probably haven't seen unctional
program design before.
If you know functional design, the book will gently introduce you to
pattern-bsed programming in Java.
If you don't know it, Felleisen and riedman will teach
you a powerful new way of thinking that you should add to your design toolbox.
Enjoy the pizzs!
Ralph E. Johnson
Champaign, Illinois
Copyrighted Material
x
Preface
An object- oriented
reusable program
quickly build large new programs
and program ragments . In the ideal cse, the programmers do not mod iy any existing code
but simply glue together components and add a few new ones. This reusability of comp onents ,
however, does not come for ree. It requires a well- designed object-oriented language and a strict
discipline of programming.
programming language enables a programmer to construct
components. With such components, other programmers can
( abstract )
language hs a simple
semantic model, which greatly helps programmers to express themselves. In addition, Java
implementations automatically manage the memory a program uses, which frees programmers
rom thinking about machine details and encourages them to focus on design.
Java is a such a language, and this
book
introduces its object-oriented elements:
clsses, ields, methods, inheritance, and interfaces.
The book ' s
This small core
patterns, the key elements of a
that enhances code reuse. Design patterns help programmers organize
their object- oriented components so t hat they properly implement the desired computatio nal
process. More importantly s till , des ign patterns help communicate important properties about
a program component. If a component is an instance of an explicitly formulated pattern and
documented s such, ot her programmers can easily understand its structure and reuse it in their
own programs, even without access to the component's source.
second goal is to introduce the reader to design
programming discipline
THE INTENDED AUDIENCE
book is primarily intended for peopl--practicing programmers, instructors and students
wish to study the essential elements of object-oriented programming and the idea
of design patterns. Readers must have some basic programming experience. They will beneit
most from the booi f they understand the principles of functional design, that is, the design
of program ragments bsed on their input -output behavior. An introductory computer science
course that uses Scheme ( or ML ) is the best way to get familiar with this style of design, but it
is not required .
The
alik--w ho
WHAT THIS BOOK IS NOT ABOUT
Java provides many useful
features and libraries beyond its object-oriented core. While these
elements are important for professional programming, their coverage would
dist ract rom the book's important goals: object-oriented programming and the use of design
patterns. For that reson, this book is not a complete introduction to Java. Still, readers
who mster its contents can quickly become skilled Java programmers with the supplementary
sources listed in the Commencement.
additional Java
The
literature on design
patterns evolves
quickl y.
Thus,
there is quite a bit more to patterns
of the patterns we use
than an introductory book could intelligibly cover. Yet, the sim plicity
and the power
that they
provide should
encourage
readers
to study the additional references
about patterns mentioned at t he end of the book.
ACKNOWLEDGMENTS
We are indebted to many people for their contribu tions and ssistance throughout the devel­
opment of this book. Several extensive discussions with Shriram Krishnamurthi, Jon R ossie ,
Copyrighted Material
i
and Mitch Wand kept us on track; their detailed comments deeply inluenced our thinking at
critical junctures.
Michael Ashley, Sundar Balasubramaniam, Cynthia Brown, Peter Drake,
Bob Filman, Robby Findler, Steve Ganz, Paul Graunke, John Greiner, Erik Hilsdale, Matthew
Kudzin, Julia Lawall, Shinn-Der Lee, Michael Levin, Gary McGraw, Benjamin Pierce, Amr
Sabry, Jonathan Sobel, and George Springer read the book at various stages of development and
their comments helped produce the inal result. We also wish to thank Robert Prior at MIT
Press who loyally supported us for many years and fostered the idea of a "Little Java." The book
greatly beneited from Dorai Sitaram's incredibly clever Scheme typesetting program
S.X.
Finally, we would like to thank the National Science Foundation for its continued support
and especially for the Educational Innovation Grant that provided us with the opportunity to
collaborate for the pst year.
READING GUIDELINES
Do not rush through this book. Allow seven sittings, at lest. Read carefully. Mark up the book
or take notes; valuable hints are scattered throughout the text. Work through the examples,
don't scan them. Keep in mind the motto "Think irst, experiment later."
The book is a dialogue about interesting Jaa programs.
Ater you have understood the
examples, experiment with them, that is, modiy the programs and examples and see how they
behave. Since most Java implementations are unfortunately batch interpreters or compilers, this
requires work of a repetitive nature on your side. Some hints on how to experiment with Java
are provided on the following pages.
We do not give any formal deinitions in this book. We believe that you can form your own
deinitions and thus remember and understand them better than if we had written them out for
you. But be sure you know and understand the bits of advice that appear in most chapters.
We use a few notational conventions throughout the text to help you understand the
programs on several levels.
words.
The primary conventions concern typeface for diferent kinds of
Field and method names are in italic.
Bsic data, including numbers, booleans, and
constructors introduced via datatypes are set in sans serif.
Keywords, e.g., class, abstract,
return and interface are in boldface. When you experiment, you may ignore the typefaces
but not the related framenotes. To highlight this role of typefaces, the programs in framenotes
are set in a typewriter face.
Food appears in many of our examples for two resons.
than abstract ideas.
( This
is not
a
First, food is esier to visualize
good book to read while dieting. )
We hope the choice of
food will help you understand the examples and concepts we use. Second, we want to provide
you with a little distraction. We know how frustrating the subject matter can be, and a little
distraction will help you keep your sanity.
You are now ready to start. Good luck! We hope you will enjoy the experiences waiting for
you on the following pages.
Bon appetit!
Matthis Felleisen
Daniel P. riedman
xii
Copyrighted Material
EXPERIMENTING WITH JAVA
Here are some hints on how to
1.
Create a ile that contains
a
experiment with
a) if the clss does not contain any
c) if the clss
hs
two ields, say
{
and y,
x
3.
"
getClass 0 getNme 0
+
() ; }
+
"
+
"
(
"
+
x
+
+
"
(
"
+
x
+
"
"
)
"
;
}
"
+
use
{
public String t oString ( )
return "new
or M, add a toString
ields, use
getClass() . getNme 0
+
clsses.
superscript V, V, I,
use
x,
public String toString()
"
with a
getClass () . getNme ()
+
b) if the clss hs one ield, say
return "new
end
{
public String toString()
"
of
complete hierarchy
To each clss whose name does not
method according to these rules:
2.
return "new
Java:1
.
"
y
+
If) If; }
Add the following clss at the bottom of the ile:
class Main
{
public static void main(String args[
new
DataType_or_Interface y
]) {
=
System.out.println(
.
.
.
.
.
.
); } }
create the object y with wh i ch you wish to
With DataType_oLlnterface y = new
experiment. T hen replace
with the example expression that you would like to experiment
with. For example, if you wish to experiment with the distnceToO method of MhattanPt
s deined in chapter 2, add the following deinition to the end of your ile:
_,
.
.
.
.
.
.
class Main {
public static void main(String rgs[
PointD y
=
new MhattanPt(2,8);
System.out.println( y.distnceToO()
lSee Arnold and
now,
just follow
Gosling [lJ
them
s
you
for
details
on how they
read this book.
]) {
); } }
work. These
Copyrighted Material
hints make
little
sense
out of context, so for
X111
If
you wish to experiment with a sequence of expressions that modiy y,
s
in
chapter 10, e.g.,
y.­
y.­
y.- -
replace
.
. . . . . with
+
y.­
y.- -
+
"\n
"\n
"
+
"
+
y.-
For example, if you wish to experiment with the methods of Pi emM
add the following deinition to the end of your ile:
class Main
{
public static void main(String rgs[
PiemnI y
=
new
PiemM();
]) {
System.out.println (
y.addTop (new nchovyO)
+
"\n"
+
y. addTop (new nchovy 0)
+
"\n"
+
y.substTop (new Tna () ,new nchovy (»
4.
); } }
Finally, compile the ile and interpret the clss Main.
XIV
Copyrighted Material
s
deined in
chapter 10,
A Little Java, A Few Patterns
Copighted Mateial
lo
@�l� �
Copyrighted Material
1
Is 5 an integer?
2
Is this a number: -23?
3
Is this an integer: 5.32?
What type of number is 5?
Yes, it is.
Yes, but we don't use negative integers.
No, and we don't use this type of number.
int.1
1 In Java, int stands for "integer."
Quick, think of another integer!
5
How about 19?
What type of value is true?
6
boolean.
What type of value is false?
7
boolean.
Can you think of another boolean?
8
No, that's all there is to boolean.
What is int?
What is boolean?
What is a type?
What is a type?
9
10
11
12
A type.
Another type.
A type is a name for a collection of values.
Sometimes we use it
s
if it were the
collection.
Can we make new types?
Moden Toys
13
We don't know how yet.
Copyrighted Material
3
Draw the picture that characterizes the
14
Is this it?
essential relationships among the following
clsses.
I
I
I
abstract class
class
Salt
class
Pepper
SeasoningV {}
extends
SeasoningV {}
extends
SeasoningV {}
D This superscript is a reminder that the clss is a
datatype. Lower superscripts when you enter this kind of
deinition in a ile: SeasoningD.
SeasoningV is a datatype,
Pepper are its variants.
Yes. We say
Salt
and
and
a
Yes, it is, because new
Salt, and
SeasoningV
instance of
SaitO
also a
Seasoningv?
17
And
new
Oay. But aren't all three clsses introducing
new types?
16
Yes, in a way. Now, is
new
15
It's also
a
SaitO
creates an
every instance of
Salt
is
SeasoningV,
because new PepperO
Pepper, and every
also a Seasoningv.
creates an instance of
PepperO?
instance of
What are abstract, class, and extends?
,.
Pepper
is
Esy:
abstract class introduces a datatype,
clss introduces a variant, and
extends connects a variant to a datatype.
Is there any other
Seasoningv?
19
No, because only
SeasoningV
1
1 Evaluating new Salt
Salt
()
and
Pepper
extend
twice does not produce the same
value, but we ignore the distinction for now.
4
Copyrighted Material
Chapter 1
Correct,
Salt
and
Pepper
variants of the datatype
we seen a datatpe like
Let's deine more
I
clss
Thyme
are the only
Seasoningv. Have
SeasoningV before?
We can have lots of
I
SeasoningV { }
22
And then there were four.
No, but boolean is a type that also hs just
two values.
21
SeasoningVs.
extends
20
clss
Sage
SeasoningVs.
extends
SeasoningV {}
Yes.
What is a Cartesian point?
23
It is bsically a pair of numbers.
What is a point in Manhattan?
24
An intersection where two city streets meet.
CatesianPt and ManhattanPt difer
Salt and Pepper?
How do
rom
I
25
Each of them contains three things between
{
and
}.
The X and the yare obviously the
coordinates of the points. But what
abstract class
PointV {}
is the
remaining thing above the bold bar?1
CartesianPt extends PointV {
int Xi
int Yi
CatesianPt(int _x,int _ y) {
class
X
=
_Xi
Y = -Yi
}
}
ManhattanPt extends PointV {
int Xi
int Yi
ManhattanPt(int -x,int _y) {
clss
X
=
_Xi
Y = -Yi
}
}
Moden Toys
1
This bar indicats the end of the constructor deinition. It
is used s an eye-catching seprator. We recommend that
you use
/I
------------------------------
when you enter it in a ile.
Copyrighted Material
5
The underlined occurrences of
and
ManhattanPt
Catesian Pt
2
6
How do we use these constructors?
introduce the constructors
of the respective variants.
A constructor is used with
new
to create
27
Obvious!
new instances of a class.
CatesianPt
When we create a
new
like this:
28
we use the constructor in the deinition of
Catesian Pt.
Correct. Is this a
new
29
Manhattan Pt:
Catesian Pt whose
2 and whose y ield is 3. And
because CatesianPt extends PointV, it is
also a Pointv.
So now we have created a
x
CatesianPt(2,3),
ield is
Yes, and its
x
ield is 2 and its y ield is
3.
Manhattan Pt(2,3)?
30
Isn't all this obvious?
Mostly, but that means we have used
constructors before without deining them.
How does that work?
When a class does not contain any ields, s
in
Salt
and
Pepper,
31
a constructor is included
And that's the constructor we used before,
right?
by default.
Yes, that's correct. Default constructors
3
2
Good. But what is
new
PointVO?
never consume values, and, when used with
new,
always create objects without ields.
33
An abstract clss is by deinition
incomplete, so
new
That makes sense. Let's move on.
cannot create an
instance rom it.
6
Copyrighted Material
Chapter 1
Do the following clsses deine another
34
Yes, they deine a datatype
and
two variants.
datatpe with variants?
I
I
abstract class Numv
{}
class Zero extends
Num v {}
O n e M oreThan
extends
class
OneMoreThan
Numv {
Numv predecessor;
OneMoreTh an ( Num V
predecessor
=
_Pi
}
_p )
{
}
Draw the picture, too .
3
Is this a Numv:
new
Is this
5
a
36
Numv:
OneMoreThan
SaitO
is a
Yes, because OneMoreThan constructs
Numv from a
OneMoreThan(
new Zero())?
new
How does
Obviously, just like new
Seasoningv.
Zero()?
One MoreThan
37
do that?
a
and every instance of
is also a Numv.
Numv,
We give it new
ZeroO,
which is a Numv, and
it constructs a new Numv.
And what does it mean to construct this new
3
8
This new instance of
OneMoreThan
with a single ield, which is called
instance?
is a value
predecessor. In our example, the ield is
new ZeroO.
Does predecessor always stand for an
instance of Zero?
39
No, its type says that it stands for a N umv ,
which , at the moment, may be either a Zero
or a
Moden Toys
OneMoreThan.
Copyrighted Material
7
40
What is
OneMoreThan(
new OneMoreThan(
new Zero()))?
new
A Numv, because OneMoreThan constructs
an instance from a Numv and we agreed
that
new
OneMoreThan(
ZeroO)
new
is a Numv.
41
What is
new
OneMoreThan(
1 We use the word "nonsense" to refer to expressios for
O)?
Is new
That is nonsense,l because 0 is not a N u mv.
which Java cannot determine a type.
ZeroO
the same
s
42
O?
No, 0 is similar to, but not the same
new
Is
43
new
OneMoreThan(
new ZeroO)
1
s,
ZeroO.
is similar to, but not the same
new
s,
OneMoreThan(
new Zero()).
like
1?
44
And what is
4.
OneMoreThan(
new OneMoreThan(
new OneMoreThan(
new OneMoreThan(
new Zero()))))
new
similar to?
Are there more N u mvs than booleans?
Are there more Numvs than ints?
45
46
Lots.
No.1
1
This answer is only conceptually correct. Java limits the
number of ints to approximately 232.
8
Copyrighted Material
Chapter 1
What is the diference between new
Zero()
47
Esy: new
Zero()
is an instance of
Zero
and,
by implication, is a NumD, wheres 0 is an
and O?
into This makes it diicult to compare them,
but we can compare them in our minds.
48
Correct. In general, if two things are
So are types just names for diferent
collections with no common instances?
instances of two diferent bsic types, they
cannot be the same.
The primitive types (int and boolean) are
49
What are non-bsic types?
distinct; others may overlap.
Clss deinitions do not introduce primitive
types. For example, a value like new
is not only an instance of
5
0
And what is that?
Zero()
Zero, but is also a
Zero. Indeed, it
NumD, which is extended by
is of any type that
NumD
extends, too.
Every clss that does not explicitly extend
51
This must mean that everything is an
52
Okay.
Object.
another clss implicitly extends the clss
Object.
Almost. We will soon see what that means.
The First Bit of Advice
hen specifying a collection of data,
use abstract classes for datatypes and
extended classes for variants.
Moden Toys
Copyrighted Material
9
53
What do the following deine?
I
They deine a new datatype and its two
variants. The irst variant contains a ield of
abstract class
LayerD {}
type
Object.
Base extends LayerD {
Object OJ
Base(Object _0) {
0= _OJ}
class
}
Slice extends LayerD {
LayerD I;
Slice(LayerD -l) {
I
_lj }
class
=
}
54
What is
Base(
new Zero())?
It looks like an instance of
means it is also a
new
55
And what is
Base(
new Salt())?
new
LayerD
Base,
and an
It also looks like an instance of
which
Object.
Base.
But
how come both
new
Base(
Zero())
new
and
new
Base(
SaitO)
new
are instances of the same variant?
They are, because everything created with
new is an
Object,
the clss of all objects.
56
Hence, we can use both
new
ZeroO
and
new
SaitO
for the construction of a
an
10
Base,
which requires
Object.
Copyrighted Material
Chapter 1
Is anythin g else an
57
Object?
We said that only things created with new
are
O bjects
.
1
1 Arrays and strings are objects, too. We don't discuss
them.
58
Correct. Is this a LayerV ;
new
5 is not created with
new,
so this must be
nonsense.
Base(
5)?
Is this a L ayer
new
V
59
;
Correct again! How about this
false
is not created with new, so this must be
nonsense, too.
Base(
false)?
Layerv:
60
Guess how we create a LayerV rom
false?
This must mean that
Integer
creates an
object from an into
Base(
new I nteger( 5))?
new
61
Esy now:
new
Base(
Boolean(false)).
new
Is it conusing that we need to connect int
with
Integer
and boolean with
Ready for more?
Moden Toys
62
Too much cofee does that.
Boolean?
63
Can't wait.
Copyrighted Material
11
�Q
2g \�
(�)f�
Copyrighted Material
Sure, we just talked about them. But what
Remember points?
are these labeled ovals about?
abstract class PointD {
}
- (�
Point
-') --
---
clss CatesianPt extends PointD {
i nt x;
int y;
CartesianPt(int _x , int _y) {
x _x;
y = -y; }
=
}
-(
CartesianPt
)
­
class ManhattanPt extends PointD {
i nt x;
int y;
ManhattanPt(int _x,int _y) {
x = _x;
y = -y; }
}
-(
ManhattanPt
)­
We will ind out soon. Did you notice the big
2
It must be for drawing the picture of the
white space on the right?
clsses.
How far is
If the Empire State Building is the origin, we
new ManhattanPt(3,4)
have to walk seven blocks:
3
over,
4 up.
rom the Empire State Building?
And how far is
new CatesianPt(3,4)
5, which is )32 + 42.
from the origin?
Methods to OUf Madness
Copyrighted Material
13
methods distanceToO usi ng {, }, (
), ;, return, int, +, L:J, and 2 which
Write the
.
,
5
Of course, you can't write these methods ,
yet. Oay, you deserve something sweet for
,
determine how far a point is from the origin.
enduring this lst question .
i nts , which represent the distances to the
What do the methods produce?
origin.
Here they are.
They correspond to the unexplained labels in
the deinition of the dat atyp e and its
abstract int distance ToOO;
variants.
Point
int distanceToOO {
return L 'x2 + y2J \ }
C artesi anPt
int distanceToOO {
return x + Yi }
M a nhat tanPt
To what do Point, CartesianPt , and
ManhattanPt in the boxes refer?
1 hen you enter this in a
ile, use
(int)Math. sqrt (x.x+y.y).
Math is a clss that contains sqrt s a (static) method. Later
we will se what (int) means.
The labels remind us that we need to insert
these methods into
PointD, CatesianPt,
8
That's simple enough.
and
ManhattanPt.
•
How many tImes have we
distance ToO?
dei ned
the method
9
Three times, but the irst one difers rom the
other two. It is labeled
abstract,
while the
others are not preceded by a special word.
14
Copyrighted Material
Chapter 2
Do abstract metho d s belong to th e
10
Yes, they always do.
abstract clss?
An abstract method in
,
n
abstract clss
II
int rod uces n o bli gat ion which says that all
Okay.
con crete clsses that extend this abstract
clss! mus t contain a matching method
deinition.
1 Directly or indirectly. That is, the concrete clss may
extend an abstract clss that extends the abstract clss with
the obligation nd so on.
What is the value of
12
7.
13
We determine the value of
new ManhattanPt(3,4)
. distance ToOO?
How do we arrive at that value?
x+y,
w it h x re pla ced by
What is the value of
14
l XJ
compute?
Time for a short break?
y replaced by
4.
5, because that is the value of
;x2 + y2
new CatesianPt(3,4)
. distance ToOO?
What does
3 an d
with x
15
re pl aced
by 3 and
y replaced by
4.
The largest int that does not excee d the
square root of x.
16
An apple a day keeps the dentist away. A
cup of cofee does not.
Methods to Our Madness
Copighted Mateial
15
Here is another datatype with its variants.
17
What is diferent about them?
abstract clss Shishv {
}
-(
Shish
It is e
Numv
but hs more vriants.
)-
class Skewer extends Shishv {
}
.ew_e_r _�)- C-_S.k_
class Onion extends Shishv {
Shishv s;
Onion(ShishV _s) {
s =
s; }
_
}
- C-_O_n_i_on_�)­
class lamb extends Shishv {
Shishv s;
lamb(ShishV _s) {
s = _s; }
}-
C-_L::a.m..
b_ ) .
_
class Tomato extends Shishv {
Shishv s;
Tomato(ShishV _s) {
s =
s; }
_
}
-(
Tomato
)-
Did you notice the big space on the right?
16
18
Yes, isn't it for drawing the picture of the
clsses?
Cophted Maeial
Chapter 2
Construct a
19
Shishv.
How about
new SkewerO?
Yes, every
Skewer is
also a
Shishv.
How
20
21
And a third?
Here's one:
new Onion(
new Skewer() ) .
about another one?
Here's one more:
new Onion(
new Lamb(
new Onion(
new Skewer()) ) ) .
Onions
new SkewerO?
on this
Shishv :
Onions
on this
Shishv :
Are there only
Are there only
22
true, because there is neither Lamb
Tomato on new Skewer O.
nor
23 true.
new Onion(
new Skewer() ) ?
And how about:
24
new Lamb(
new Skewer()) ?
Is it true that
25
false.
true.
new Onion(
new Onion(
new Onion(
new Skewer())) )
contains only Onions?
And inally:
26
false.
new Onion(
new Lamb(
new Onion(
new Skewer() ) ) ) ?
Methods to Our Madness
Copyrighted Material
17
onlyOnions1 using {, }, ( ,
,;, true, false, return, and boolean.
Write the methods
),
27
Of course, you can't write these methods,
yet. Okay, you deserve a lollipop for
enduring this kind of question again.
1 A better ame for these methods ould be
nothingButOn1ona.
And what do they produce?
Here are the methods.
28
booleans.
29
Yes. We said above that the labeled ovals in
the center of the blank lines in the above
abstract boolean onlyOnionsO;
clss deinitions tell us where to put the
boxes with the corresponding labels.
Shish
: boolean onlyOnionsO {
return true; }
Skewer
boolean onlyOnionsO {
return s.onlyOnionsO; }
Onion
boolean onlyOnionsO {
return false; }
Lamb
boolean onlyOnionsO {
return false; }
Tomato
Did you notice the labels in the boxes?
Good. How many methods have we deined?
18
30
Five, but the irst one is
others
re
Copighted Mateial
concrete.
abstract;
the
Chapter 2
abstract methods
abstract class?
Do
belong to the
Shishv
onlyOnions?
Does each variant of
method called
contain a
31
32
Yes, we said so.
Yes, because
Shishv contains an abstract
onlyOnions that obligates
method called
each variant to deine a matching, concrete
method.
33
Is this always the cse?
What do these concrete methods consume?
What do these concrete methods produce?
34
35
36
What is the value of
new Onion(
new Onion(
new Skewer(»)
.onlyOnionsO?
And how do we determine the value of
37
new Onion(
new Onion(
new SkewerO»
.onlyOnions()?
Which deinition of
Always.
•
•
Nothing, Just s the
abstract
booleans, just s the
method says.
abstract
method says.
true.
We will need to pay attention to the method
deinitions.
onlyOnions
to determine the value of
new Onion(
new Onion(
new Skewer(»)
. onlyOnions ()?
Methods to Our Madness
must we use
38
This object is an instance of
need to use the deinition of
belongs to the
Copighted Mateial
Onion
Onion, so we
onlyOnions that
variant.
19
What follows the word return in the
onlyOnions method in Onion?
What
is the ield s of the object
39
s.onlyOnions{).
40
It
new Onion(
new Onion(
new Skewer() ))?
Does s always stand for an
is
new Onion(
new Skewer()) ,
isn't it?
41
Onion?
42
Then what is s.onlyOnions()?
No, it hs type Shishv, and it can stand for
any variant of Shishv : Skewer, Onion, Lamb,
or Tomato.
It
should be
new Onion(
new Skewer() )
.onlyOnionsO,
right?
Why do we need to know the meaning of
43
new Onion(
new SkewerO)
. onlyOnions O?
Because the answer for
new Onion (
new Skewer() )
. onlyOnions 0
is also the answer for
new Onion(
new Onion(
new SkewerO) )
. onlyOnionsO·
.
How do we determine the answer for
new Onion(
new Skewer())
.onlyOnions()?
20
44
Let's see.
Copighted Mateial
Chapter 2
Which deinition of
onlyOnions
must we use
45
new Onion(
new SkewerO)
.onlyOnionsO?
belongs to the
What follows the word
onlyOnions
method in
W hat is the ield
s
return
Onion?
in the
46
47
of the object
new Onion(
new Skewer())?
Then what is
This object is
n
instance
of Onion, so we
onlyOnions that
need to use the deinition of
to determine the value of
48
s.onlyOnionsO?
s.
Onion
variant.
onlyOnions O.
new SkewerO.
It is
new SkewerO
.onlyOnionsO,
just s we would have expected.
Why do we need to know the meaning of
49
Because the answer for
new SkewerO
. onlyOnions 0
new SkewerO
. onlyOnions O?
is also the answer for
new Onion(
new SkewerO)
. onlyOnions 0 ,
which in turn is the answer for
new Onion(
new Onion(
new Skewer()))
.onlyOnionsO·
Hw do we determine the answer for
new Skewer O
.onlyOnionsO?
Methods to Our Madness
50
We need to determine one more time which
version of
Copyrighted Material
onlyOnions
we must use.
21
Is
51
new
Obviously.
SkewerO
a
Skewer?
5
Then what is the answer?
2
53
Why?
true.
Because
in
54
Are we done?
true is what the onlyOnions method
Skewer always returns.
Yes !
The answer for
new
Onion(
On i o n (
new
.
is
new Skewer()))
only Onions 0
the sme s the answer for
Onion(
SkewerO)
.onlyOnionsO,
new
new
which is the same s the answer for
SkewerO
.onlyOnionsO,
new
which is
true.
What is the
55
value of
Onion(
new Lamb(
new Skewer()))
. onlyOnionsO?
new
Which deinition of only Onions must we use
to determine the value of
Onion(
Lamb(
new Skewer()))
.onlyOnionsO?
new
new
22
56
false,
isn't it?
This object is an instanc e of Onion, so we
of onlyOnions that
belongs to the Onion arint.
need to use the de in iti o n
Copyrighted Material
Chapter 2
What follows the word
onlyOnions
method in
What is the ield
s
return
Onion?
in the
57
58
of the object
new Onion(
new Lamb(
new Skewer()))?
Then what is
s. onlyOnions() .
It is the object built from
new Lamb(
new Skewer()).
59
s.onlyOnions()?
I t is
new Lamb(
new Skewer())
onlyOnions() ,
·
of course.
Why do we need to now the meaning of
60
Because the answer for
new Lamb(
new Skewer())
onlyOnions()
new Lamb(
new Skewer())
. onlyOnions () ?
·
is also the answer for
new Onion(
new Lamb(
new Skewer()))
onlyOnions o.
·
How do we determine the answer for
61
new Lamb(
new Skewer())
.onlyOnions()?
And?
And now what is the answer?
We determine which version of
onlyOnions
to use.
62
63
We use the one that belongs to
false,
because
false
Lamb.
follows the word
return
in the corresponding method deinition in
Lamb.
Methods to OUf Madness
Copyrighted Material
23
64
Are we done?
Yes! The answer for
new Onion(
new Lamb(
new Skewer()))
. onlyOnions0
is the same s the answer for
new Lamb(
new Skewer())
. onlyOnionsO,
which is
false.
Describe the methods
only Onions
(i. e.,
the function )
65
Here are our words:
"The methods determine for
in your own words.
a S hish v
whether its contents are edible by an onion
lover."
Describe how the methods
function )
(i.e.,
the
onlyOnions accomplish
66
Here are our words again:
"For each layer of th e
this.
Onion,
Shishv,
except for
the corresponding method knows
whether it is go od or bad. The method for
Onion needs to determine whether the
remaining layers are only
a
Is
a
Is
a
67
new Tomato(
new SkewerO)
Shishv?
68
new Onion(
new Tomato(
new Skewer()))
Shishv?
And how about another
24
69
sitting
on
Yes.
The obj ect
new Tomato(
new SkewerO)
is an instance of Shishv,
an Onion around it.
Tomato?
Onions
Skewer."
so we can also wrap
Sure.
Copyighted Mateial
Chapter 2
70
Is
new Tomato(
new Onion(
new Tomato(
new SkewerO)
Of course, there is no Lamb on it.
a vegetarian shish kebab?
71
And
new Onion(
new Onion(
new Onion(
new Skewer())))?
Deine the methods
is Vegetarian,
which return true
if
(i.e.,
Yes, it is a vegetarian shish kebab, because it
only contains
the unction)
the given object does not
72
Onions.
That's no big deal now.
abstract boolean is Vegetarian 0;
contain Lamb.
Shish
Hint: The method for tomatoes is the same
s
the one for onions.
boolean isVegetarian 0 {
return true; }
Skewer
boolean isVegetarian 0 {
return s.isVegetarianOi }
Onion
boolean isVegetarian 0 {
return false; }
Lamb
boolean isVgetarian 0 {
return s.isVegetarianOi }
Tomato
Methods to Our Madness
Copighted Mateial
25
How many methods have we deined?
abstract methods
abstract class?
Do
belong to the
Shishv contain a
isVegetarian?
Does each variant of
method called
73
74
75
Five: one
abstract,
the others concrete.
Yes, they always do.
Yes, because
Shishv contains an abstract
isVegetarian.
method called
Is this always the cse?
76
Always.
What do these concrete methods consume?
77
Nothing, just s the
What do these concrete methods produce?
78
booleans, just
abstract
s the
method says.
abstract method
says.
The Second Bit of Advice
hen writing a function over a
datatype, place a method in each of the
vaiants that make up the datatype. If
a ield of a variant belongs to the same
datatype, the method may call the
corresponding method of the ield in
computing the function.
26
Copyrighted Material
Chapter 2
Collect all the pieces of
Shishv.
datatype.
Here is the
abstract class Shishv {
abstract boolean onlyOnions();
abstract boolean isVegetaian();
}
79
There are two methods per variant.
class Skewer extends Shishv {
boolean onlyOnionsO {
return true; }
boolean isVegetarian 0 {
return true; }
}
class Onion extends Shishv {
Shishv s;
Onion(ShishV _8) {
s = _8; }
boolean onlyOnionsO {
return s.onlyOnionsO; }
boolean is Vegetarian 0 {
return 8.isVegetarianO; }
}
class Lamb extends Shishv {
Shishv s;
Lamb(ShishV _s) {
s = _s; }
boolean onlyOnions () {
return false; }
boolean is Vegetarian 0 {
return false; }
}
class Tomato extends Shishv {
Shishv s;
Tomato(ShishV _8) {
s = _s; }
}
Methods to OUT Madnss
boolean onlyOnionsO {
return false; }
boolean isVegetarian 0 {
return s.isVegetarianO; }
Copyrighted Material
27
What do the following deine?
abstract class Kebabv {
}
-(
80
They deine a datatype an d four variants
that are similar in shape to Sh ishD
)-
Kebab
class Holder extends KebabD {
Object OJ
Holder( Object 0 ) {
0= O J }
_
_
}
-C
_�)-
H_o_ld_e_
r
__
class Shallot extends KebabD {
KebabD k;
Shallot(KebabV k ) {
kj }
k
_
=
}
_
-(
Shallot
)-
class Shrimp extends KebabD {
KebabD k;
Shrimp(KebabV _k) {
k _kj }
=
}
-(
Shrimp
)-
class Radish extends KebabD {
KebabD k;
Radish(KebabV _k) {
k _kj }
=
}
-(
dish
)-
Don't forget the picture.
28
Copighted Mateial
Chapter 2
81
W hat is diferent about them?
82
Here are some holders.
I abstract class RodD {}
I class Dagger extends RodD {}
I class Sabre extends RodD {}
I class Sword extends RodD {}
They are placed onto diferent Holders.
Sure, a rod is a kind of holder, and every rod
is an
Object,
so
0
in
Holder
can stand for any
rod. Is it necessary to draw another picture?
Are they good ones?
Think of another kind of holder. Are you
83
tired of drawing pictures, yet?
We could move all of the food to various
forms of plates.
abstract class PlateD {}
class Gold extends PlateD { }
class Silver extends PlateD { }
class Brass extends PlateD { }
I class Copper extends PlateD {}
I class Wood extends PlateD {}
What is
new Shallot(
new Radish(
new Holder(
new Dagger())))?
Methods to Our Madness
84
It's a
KebabD.
Copyrighted Material
29
Is
a
Is
a
85
new Shallot(
new Radish(
new Holder(
new Dagger())))
vegetarian Kebabv?
86
new Shallot(
new Radish(
new Holder(
new Gold())))
Kebabv?
Is
Sure it is. It only contains radishes and
shallots.
Sure, because
s a
put on any
87
new Shallot(
new Radish(
new Holder(
new Gold())))
Gold is
a
PlateV, PlateV
is used
and radishes and shallots can be
Holder.
Sure it is. It is bsically like
new Shallot(
new Radish(
new Holder(
new Dagger()))),
a vegetarian kebab?
except that we have moved all the food from
a
Let's deine the methods
Holder,
( i. e.,
the function)
8
8
Dagger
to a
Gold
plate.
If you can, you may rest now.
is Veggie,
which check whether a kebab contains only
vegetarian foods, regardless of what
Holder
it
is on.
Write the abstract method
is Veggie.
89
That's possible now.
abstract boolean is Veggie ()
Kebab
is Veggie belongs
is Vegetarian to Shishv
Of course,
30
Copyrighted Material
to
Kebabv
and
Chapter 2
The concrete methods are similar to those
called isVegetaian. Here are two more;
deine the remaining two.
90
Except for the names of the methods and
ields, the deinitions are the same s they
were for Shishv
boolean is VeggieO {
return false; }
boolean is VeggieO {
return true; }
Shrimp
Holder
boolean is VeggieO {
return k.isVeggieO; }
boolean isVeggieO {
return k.isVeggieO; }
Radish
Shallot
What is t he
value of
91
new Shallot(
new Radish(
new Holder(
new Dagger())))
is Veggie O?
true.
.
What
is
92
new Shallot(
new Radish(
new Holder(
new Dagger())))?
What
is the value of
new Shallot(
new Radish(
new Holder(
new Gold())))?
Methods to Our Madness
Kebabv,
instance of the
93
new Shallot(
new Radish(
new Holder(
new Gold())))
.isVeggieO?
And what is
It is a
94
but
we also know that it is an
Shallot
variant.
It is true, too.
It is also a
Kebabv,
Holder will
do.
Copyrighted Material
because any
kind of
31
What type of value
is
95
boolean.
96
boolean.
97
boolean.
Shallot(
new Radish(
new Holder(
new I nteger( 52))))
.isVeggieO?
new
What type of value is
Shallot(
new Radish(
new Holder(
new OneMoreThan(
new Zero()))))
new
. is Veggie O?
What ty pe of
value
.
is
Shallot(
new Radish(
new Holder(
new Boolean(false))))
is Veggie O?
new
Does that mean
is Veggie
kinds of Holders?
What is the holder of
works for all ive
98
Yes, and all other kinds of
could possibly think of.
99
All the food
Shallot(
new Radish(
new H older(
new Dagger())))?
is on a D agg er
Objects that we
.
new
What is the holder of
100
All the
Shallot(
new Radish(
new Holder(
new Gold() )))?
new
32
Copyrighted Material
food is now on a Gold plate.
Chapter 2
101
What is the holder of
All the food is on an
Integer.
new Shallot(
new Radish(
new Holder(
new Integer(52))))?
102
What is the value of
The dagger.
new Shallot(
new Radish(
new Holder(
new DaggerO)))
whatHolderO?
·
103
What is the value of
The gold plate.
new Shallot(
new Radish(
new Holder(
new Gold())))
whatHolder()?
·
104
What is the value of
An
Integer,
whose underlying int is
52.
new Shallot(
new Radish(
new Holder(
new Integer(52))))
whatHolderO?
·
What type of values do the methods
the unction ) of
whatHolder
(i.e.,
105
Is there a simple way of saying what type of
106
whatHolder.
107
Object,
Holder.
They always produce an
the type of the ield of
values they produce?
Here is the abstract method
They produce rods, plates, and integers. And
it looks like they can produce a lot more.
produce?
If we add this method to
which is also
KebabD,
then we
must add a method deinition to each of the
abstract Object whatHolder()
four variants.
Kebab
Methods to Our Madness
Copyrighted Material
33
108
What is the value of
new Holder(
new Integer(52))
whatHolderO?
new Integer(52).
.
109
What is the value of
new Holder(
new Sword())
.whatHolderO?
110
What is the value of
if
new Holder( b)
.whatHolderO
b is some object?
Deine the concrete method that goes into
111
the space labeled Holder.
new SwordO.
It is
b.
With these kinds of hints, it's esy.
Object whatHolderO {
return
0;
}
Holder
What is the value of
112
new Radish(
new Shallot(
new Shrimp(
new Holder(
new Integer(52)))))
whatHolderO?
new Integer(52).
.
What is the value of
new Shallot(
new Shrimp(
new Holder(
new Integer(52))))
.whatHolderO?
34
113
new Integer(52).
Copyrighted Material
Chapter 2
What is
ne
114
the value of
w Shrimp(
new Holder(
new Integer(52)))
. whatHolderO?
Does that
115
mean that the value of
Radish(
new Shallot(
new Shrimp(
new Holder(
new Integer(52)))))
.whatHolderO
new
new Integer(52).
Yes, all four have the same answer:
new
Integer(52).
is the same s
new Shallot(
new Shrimp(
new Holder(
new Integer(52))))
.whatHolderO,
which is the same
s
Shrimp(
new Holder(
new Integer(52)))
whatHolder 0 ,
new
.
which is the same
s
Holder(
new Integer(52))
. whatHolderO?
new
Here is the method for
116
Shallot.
Object whatHolderO {
return k. whatHolderO; }
They are all the same.
Object whatHolderO {
return k.whatHolderO; }
Shallot
Write the methods of whatHolder for Shrimp
and Radish.
Shrimp
Object whatHolderO {
return k.whatHolderO; }
Radish
Methods to Our Madness
Copighted Mateial
35
Here is the datatype and one of its variants.
117
class Shallot extends KebabD {
Kebabv k;
Shallot(KebabD _k) {
k = _kj }
abstract class KebabD {
abstract boolean isVeggie 0 j
abstract Object whatHolder()j
}
boolean isVeggieO {
return k. isVeggie 0 j }
Object whatHolderO {
return k.whatHolderOj }
class Holder extends KebabD {
Object OJ
Holder( Object _0) {
o
OJ }
=
}
There are only three let.
_
}
boolean is VeggieO {
return truej }
Object whatHolderO {
return 0; }
class Shrimp extends Kebabv {
Kebabv k;
Shrimp(KebabD _k) {
k = kj }
_
boolean isVeggieO {
return falsej }
Object whatHolderO {
return k.whatHolderOj }
Collect the remaining variants.
}
class Radish extends KebabD {
Kebabv k;
Radish(KebabD _k) {
k = _kj }
boolean isVeggieO {
return k.isVeggieOj }
Object whatHolderO {
return k.whatHolderOj }
}
Kebabv
Shallot, Shrimp, and Radish?
Are there any other
36
foods besides
118
No, these are the only kinds of foods on a
Kebabv.
Copyrighted Material
Chapter 2
119
Cn we add more foods?
Let's deine another
Sure. We did something like that when we
added
120
Kebabv
Seasoningv.
A concrete clss that extends
abstract
many
Kebabv
must
speciications say. We can deine s
Kebabvs
s we wish.
class Zucchini extends Kebabv {
Kebabv k;
Zucchini( KebabV _k) {
k _k; }
boolean isVeggie 0 {
return k.isVeggieO; }
Object whatHolderO {
return k.whatHolderO; }
=
boolean isVeggieO {
return k. is Veggie 0; }
Object whatHolderO {
return k.whatHolderO; }
}
isVeggie
to
deine these two methods. That's what the
class Pepper extends Kebabv {
Kebabv k;
Pepper(KebabV _k) {
k = _k; }
W hy does it include
Thyme nd Sage
and
whatHolder
}
methods?
s it obvious how the new methods work?
121
Totally. In both cses
the rest of the
isVeggie
Kebabv,
just checks
because green
peppers and zucchini are vegetables.
Similarly,
whatHolder
returns whatever
holder belongs to the rest of the
122
And then there were six.
Which of these points is closer to the origin:
123
Yes, now
Kebabv
Kebabv.
hs six variants.
The second one,
because its distance to the origin is 6 while
new ManhattanPt(3,4)
the irst point's distance is 7.
and
new ManhattanPt(1,5)?
Good. Which of the following points is closer
to the origin:
12.
The irst one, clearly. Its distance to the
origin is 5, but the second distance is
13.
new CartesianPt(3,4)
or
new CatesianPt(12,5)?
Methods to Our Madness
Copyrighted Material
37
We added the method
CatesianPt.
closerToO
It consumes another
to
125
CartesianPt
The deinitions are nearly identical. The
ManhattanPt consumes a
ManhattanPt and determines which of
method for
and determines whether the constructed or
the consumed point is closer to the origin.
those
two points is closer to the origin.
clss ManhattanPt extends PointD {
int Xj
int y;
ManhattanPt(int _x,int _y) {
class CatesianPt extends PointD {
int x;
int y;
CartesianPt(int _x int _y) {
x
_Xj
Y = -Yj }
,
x = -x;
=
y
int distanceToOO {
return lvx2 +y2J;}
boolean closerToO(CatesianPt p) {
return
distanceToOO ; p.distanceToOO; }
}
}
Add the corresponding method to
=
-y; }
int distanceToOO {
return x + y; }
boolean closerToO(ManhattanPt p) {
return
distanceToOO ;1 p.distanceToOO; }
1 This is the two character symbol <=.
ManhattanPt.
126
What is the value of
false.
new ManhattanPt(3,4)
.closerToO(new ManhattanPt(1,5»?
127
What is the value of
true,
obviously.
new ManhattanPt(1,5)
.closerToO(new ManhattanPt(3,4»?
128
What is the value of
new CartesianPt(12,5)
.closerToO(new CartesianPt(3,4»?
129
So inally, what is the value of
false, and true is the value of
new CatesianPt(3,4)
.closerToO(new CatesianPt(12,5».
That's nonsense.
new CatesianPt(3,4)
.closerToO(new ManhattanPt(1,5»?
38
Copyrighted Material
Chapter 2
130
Why?
The method
CartesianPts,
131
How can we x that?
closerToO can only
not ManhattanPts.
consume
We could replace
(CatesianPt p)
by
(PointD p)
in the deinition of
e
If
we do that , can
value of
st ill determine the
132
by
named
(PointD p)?
Here is the improved
(CartesianPt p)
133
13_
CatesianPt.
}
,
Is the deinit ion of
the same
s
the
CartesianPt is a PointD,
ManhattanPt is a PointD, too.
and every
Esy.
}
_
int distanceToOO {
return x + Yi }
boolean closerToO(PointD p) {
return
distanceToOO � p.distanceToOOi }
ManhattanPt.
closerToO in CartesianPt
one in ManhattanPt?
Methods to Our Madness
PointD
distanceToO.
Every
=
int distanceToOO {
return llx2+y2Ji}
boolean closerToO(PointD p) {
return
distanceToOO � p.distanceToOO; }
Improve the deinition of
CatesianPt.
clss ManhattanPt extends PointD {
int Xi
int Yi
ManhattanPt(int _x,int _y) {
x
x;
y = -Y; }
class CatesianPt extends PointD {
int x;
int y;
CatesianPt(int x int -y) {
x = _x;
Y = -Yi }
_
Yes, because the deinition of
for
obl igates every variant to provide a method
p.distanceToO()?
Why does it help to replace
closerToO
135
•
Yes, they are identical.
Copyihted Mateial
39
Correct, and therefore we can add a copy to
the abstract clss
PointV
136
Looks correct.
and delete the
deinitions from the variants.
abstract class PointV {
boolean closerTo01 (PointV p) {
return
distanceToOO ; p. distanceToOOj }
abstract int distanceToOOj
}
What else do the two point variants have in
1 The method closerToO is a
distnceToO is a hook in the
instance
137
[4].
template and the method
template method pattern
Their ields. Shouldn't we lit them, too?
common?
138
Yes. It's tricky, but here is a start.
This not only lits
x
and
Y,
it also introduces
a new constructor.
abstract class PointV {
int Xj
int Yj
PointV(int _x,int _y) {
x _Xj
Y -Yj }
=
=
boolean closerToO(PointV p) {
return
distanceToOO ; p.distanceToOOj }
abstract int distanceToOOj
}
Absolutely. And we need to change how a
CatesianPt
is built. Deine
ManhattanPt.
class CatesianPt extends PointV {
CatesianPt(int _x,int _y) {
super(_x,_Y)j }
}
40
int distanceToOO {
return l VX2 + y2 J j }
139
Mimicking this change is esy. But what
does
sup er(_ x ,_ y)
mean?
class ManhattanPt extends PointV {
ManhattanPt(int _x,int _y) {
super( _ x ,_ y)j }
}
int distanceToOO {
return x + Yj }
Copyrighted Material
Chapter 2
The expressions
140
in the
CartesianPt and ManhattanPt
PointP with the appropriate ields,
constructors
c reate a
super(_x,_y)
That's simple.
and the respective constructor guarantees
that the point
becomes a
ManhattanPt.
CatesianPt
Do we now have everthing that
characterizes
PointPs
141
in the datatyp e?
Is this a long chapter?
Methods to
or a
OUf Madness
Yes, and those things that distinguish the
two
r iants
rom each other reside in the
corresponding variants.
, ..
Yes, let's have a short snack break.
Copyighted Material
41
Copyrighted Material
Do you like to eat pizza?
abstract class
}
}
Pizzav {
)
Crust
extends
Pizzav {
(
Crust
)
-
Sausage.
Sausage extends Pizzav {
Pizzav p;
Sausage(PizzaV -p) {
p = -Pi }
class
Pizza
-
class
(
Looks like good toppings. Let's add
�-----
�-----
--
--
}
-
(
Sausage
)
-
Cheese extends Pizzav {
Pizzav p;
Cheese(PizzaV -p) {
p - p; }
class
=
}
-
(
Cheese
)
----�
--
Olive extends Pizzav {
Pizzav p;
Olive(PizzaV -p) {
p -p; }
class
=
}
-
(�
O
_l_ i ve_
_
_�) -
Anchovy extends Pizzav {
Pizzav p;
Anchovy(PizzaV -p) {
p -p; }
class
=
}
-
(
Anchovy
What's New?
)
-
Copyrighted Material
43
Here is our favorite pizza:
This loos too salty.
Anchovy(
new Olive(
new Anchovy(
new Anchovy(
new Cheese(
new Crust()))))).
new
How about removing the anchovies?
3
Let's remove them. What is the value of
That would make it less salty.
It should be a cheese and olive pizza, like
Anchovy(
new Olive(
new Anchovy(
new Anchovy(
new Cheese(
new Crust())))))
.remA10?
new
this:
Olive(
Cheese(
new Crust())).
new
new
1 A better name for these methods would be removenchovy!
but then our deinitions wouldn't it into these columns.
It should be a cheese, sausage, and olive
What is the value of
Sausage(
new Olive(
new Anchovy(
new Sausage(
new Cheese(
new CrustO)))))
remAO?
new
.
Does
remA
pizza, like this:
Sausage(
Olive(
new Sausage(
new Cheese(
new Crust())))) .
new
new
belong to the datatype
PizzaD
6
Yes, and it produces them, too.
and its variants?
44
Copyrighted Material
Chapter 3
Deine the methods that belong to the ive
7
We didn't expect you to know this one.
variants. Here is a start.
abstract
PizzaD remAO;
Pizza
PizzaD remAO {
return new CrustO; }
Crust
Deine the two methods that belong to
and
Sausage.
Olive
8
We've eaten the cheese already.
The
Olive and Sausage
Cheese method.
methods are similar
to the
PizzaD remAO {
return new Olive(p.remA()); }
PizzaD remAO {
return new Cheese(p.remA()); }
Olive
Cheese
PizzaD remAO {
return new Sausage(p.remA()); }
Sausage
The cheese, the olives, and the sausages on
Explain why we use
new
new
new
Cheese .
Olive
, and
Sausage ...
.
.
the pizzs must be put back on top of the
,
pi zza
. . .
that p.remAO
produces.
when we deine these methods.
remA must produce a PizzaD ,
so let's use new CrustO, the simplest PizzaD,
for the method in Anchovy.
The methods
10
Yes, and now the methods of
remA produce
pizzs without any anchovies on them.
PizzaD remAO {
return new CrustO; }
Anchovy
What's New?
Copyrighted Material
45
11
Let's try it out on a small pizza:
new
new
That's esy. The object is an Anchovy. So
the answer is
Anchovy(
new
CrustO.
Crust())
.emAO·
Is
I'
new
CrustO
Absolutely, but what if we had more
anchovies?
like
new
Anchovy(
new
CrustO)
without anchovy?
13
No problem. Here is an example:
new
new
new
Anchovy(
new
That's esy again. As before, the object is an
Anchovy so that the answer must still be
Anchovy(
CrustO.
Crust()))
.emAO·
Okay, so what if we had an olive and cheese
14
new
Well, this object is an Olive and its p stnds
for
on top:
new
Olive(
new
new
Anchovy(
new
Anchovy(
new
Anchovy(
new
Anchovy(
new
Cheese(
new
Cheese(
CrustO))).
CrustO))))
.emAO?
Then, what is the value of
new
Olive(p.emA())
where p stands for
new
Cheese(
new
Anchovy(
new
Anchovy(
new
46
CrustO)))?
15
It is the pizza that
new
Cheese(
new
Anchovy(
new
Anchovy(
new
CrustO)))
.emAO
produces, with an olive added on top.
Copyrighted Material
Chapter 3
16
What is the value of
Cheese(
new Anchovy(
new Anchovy(
new CrustO)))
.remAO?
new
It is
new
Cheese(p.remA()),
where p stands for
Anchovy(
Anchovy(
new Crust())).
new
new
17
And what is the value of
Cheese(
new Anchovy(
new Anchovy(
new Crust()))
.remA())?
new
It is the pizza that
Anchovy(
Anchovy(
new Crust()))
.remAO
new
new
produces, with cheese added on top.
18
Do we know the value of
Yes, we know that it produces new
Anchovy(
new Anchovy(
new CrustO))
.remAO?
CrustO.
new
Does that mean that new
CrustO
is the
19
we
No,
still have to add cheese and an olive.
answer?
Does it matter in which order we add those
20
two toppings?
Yes, we must irst add cheese, producing
new
Cheese(
Crust())
new
and then we add the olive.
So what is the inal answer?
21
It is
Olive(
Cheese(
new Crust())).
new
new
What's New?
Copyrighted Material
47
22
Let's try one more example:
new
It should be a double-cheese pizza.
Cheese(
Anchovy(
new Cheese(
new CrustO»)
.remAO·
new
What kind of pizza should this make?
23
Check it out!
The object is an instance of
Cheese
so the
value is
new
Cheese(p.emAO)
p stands for
new Anchovy(
new Cheese(
new CrustO».
where
Doesn't that mean that the result is
24
new
Cheese(
new Anchovy(
new Cheese(
new CrustO»
.remA())?
Yes, it puts the cheese on whatever we get
for
new
Anchovy(
Cheese(
new Crust()))
.remAO·
new
2
5
What about
new
Now the object is an anchovy.
Anchovy(
new Cheese(
new Crust(»)
.remAO?
2
And the answer is
new
Yes, but we need to add cheese on top.
CrustO?
Does that mean the inal answer is
new
6
21
Yes, though it's not the answer we want.
Cheese(
new Crust(»?
48
Chapter 3
Copyrighted Material
2S
What do we want?
A double-cheese pizza like
Cheese(
Cheese(
new Crust())),
new
new
because that's what it means to remove
anchovies and nothing else.
Which
remA
method do we need to change
29
to get the cheese back?
The one in
Anchovy.
Pizzav remAO {
return p.remAO; }
Anchovy
Does this
remA
still belong to
Pizzav?
30
Yes, and it still produces them.
The Third Bit of Advice
hen writing a function that retuns
values of a datatype, use new to create
these values.
We could add cheese on top of the anchovies.
What kind of pizza is
31
32
Esy, it adds cheese on top of each anchovy:
Olive(
Cheese(
new Anchovy(
new Cheese(
new Cheese(
new Anchovy(
new Crust())))))).
Olive(
new Anchovy(
new Cheese(
new Anchovy(
new Crust()))))
.topAwC10?
new
new
1
Yes, that would hide their taste, too.
new
A better name for these methods would be
topnchovvi thCheese.
Did you notice the underlines?
What's New?
33
Yes, they show where we added cheese.
Copyrighted Material
49
3.
is
new Olive(
new Cheese(
new Sausage(
new Crust())))
.topAwC()?
And what
Olive(
Cheese(
new Sausage(
new Crust()))).
new
new
35
Deine the remaining methods.
abstract
Pizzav topAwCO;
We expect you to know some of the answers.
Pizzav topAwCO {
return new Cheese(p.topAwC()); }
Pizza
:
Here we don't add any cheese, because the
pizza does not contain any anchovies:
Cheese
Pizzav topAwCO {
return new Crust(); }
Pizzav topAwCO {
return new Olive(p.topAwC()); }
Crust
Olive
Pizzav topAwCO {
return new Sausage(p.topAwC())j }
Sausage
Take
a
look at this
36
method.
Pizzav topAwCO {
return p.topAwC(); }
Anchovy
With that deinition, topAwC would give the
same results s remA. The method topAwC
in Anchovy must put the anchovy back on
the pizza and top it with cheese.
Pizzav topAwCO {
return
new
Cheese(
Anchovy(p. topA wC() ) ) ; }
new
Anchoy
50
Copyrighted Material
Chapter 3
How many layers of cheese are in the result
of
37
One, because
remA removes all the
topAwC doesn't add
anchovies, so that
( new Olive(
new Anchovy(
new Cheese(
new Anchovy(
new Crust()))))
.remA())
.topAwC()?
any
cheese.
How many occurrences of cheese are in the
38
result of
Three, because
topAwC irst adds cheese for
remA removes all the
each anchoy. Then
( new Olive(
new Anchovy(
new Cheese(
new Anchovy(
new Crust()))))
. topAwC())
.remA()?
anchovies:
Olive(
Cheese(
new Cheese(
new Cheese(
new Crust())))) .
new
new
Perhaps we should replace every anchovy
39
We just did something like that.
40
Yes, and it does more. Once all the cheese is
with cheese.
s it true that for each anchovy in
x
added, the anchovies are removed.
x.topAwC().remA()
adds some cheese?
41
So
Aha!
x. topAwC() . remA()
is a way to substitute all anchovies with
cheese by looking at each topping of a pizza
and adding cheese on top of each anchoy
and then looking at each topping again,
including all the new cheese, and removing
the anchovies.
What's New?
Copyrighted Material
51
Here is a diferent description:
"The methods look at each topping of
a
42
cheese."
Deine the methods that match this
subAbC.1
a
skeleton.
PizzaJ subAbC() {
return new CrustOi }
pizza and replace each anchoy with
description. Call them
Here is
Crust
Here is the
abstract method.
abstract
PizzaJ subAbC() {
return new Cheese(p.subAbC())j }
PizzaJ subAbCO;
Pizza
Cheese
Pizza) subAbCO {
return new Ofive(p.subAbCO); }
Olive
Pizza) subAbCO {
return
;
}
Anchovy
Pizza) subAbCO {
return new Sausage(p.subAbC())j }
Sausage
1 A better name for these methods would be
substi tutenchovybyCheese.
43
Does this skeleton look familiar?
Yes, this skeleton looks just like those of
topAwC and emA.
Deine the method that belongs in
Anchovy.
44
Here it is.
Pizza) subAbC() {
return new Cheese(p.subAbC())j }
Anchovy
52
Chapter 3
Copyrighted Material
45
Collection time. 1
PizzaD {
PizzaD emAO;
abstract PizzaD topAwCO ;
abstract PizzaD subAbCO;
The clsses are getting larger.
Olive extends PizzaD {
PizzaD p;
Olive(PizzaD -p) {
p = Pi }
abstract class
clss
abstract
-
}
Crust extends PizzaD {
Pi zaD remAO {
return new C ru stOj }
PizzaD topAwCO {
return new CrustO ; }
PizzaD subAbCO {
return new CrustO; }
class
}
PizzaD remAO {
return new Olive(p.remA())j }
PizzaD topAwCO {
return new Olive(p.topAwC()); }
PizzaD subAbCO {
return new Olive(p.subAbC()); }
Anchoy extends PizzaD {
PizzaD p;
Anchoy( Pi zzaD -p) {
p = -Pi }
}
class
Cheese extends PizzaD {
PizzaD p;
Cheese( PizzaD -p) {
p = Pj }
class
PizzaD remAO {
return p.remAO; }
PizzaD t op AwC O {
-
PizzaD remAO {
return new Cheese(p.remA())j }
PizzaD topAwCO {
return new Cheese(p.topAwC())j }
PizzaD subAbCO {
return new Cheese(p.subAbC())j }
}
return
Cheese(
Anchoy(p.topAwC())); }
PizzaD subAbCO {
return new Cheese(p.subAbC()); }
new
new
}
Sausage extends PizzaD {
PizzaD p;
Sausage(PizzaD -p) {
p = -Pi }
class
1
Ths is similr to the intepreter and composite
pattes
[41.
Iat's New?
}
PizzaD remAO {
return new Sausage(p.remA()); }
PizzaD topAwCO {
return new Sausage(p.topAwC()); }
PizzaD subAbCO {
return new Sausage(p.subAbC()); }
Copyrighted Material
53
Let's add more
Pizzav
Here is one addition:
46
foods.
47
Spinach.
Good idea.
Yes, we must deine three concrete methods
for each variant of
Spinach extends Pizzav {
Pizzav p;
Spinach(PizzaV -p) {
p -p; }
Pizzav
class
=
}
Pizzav remAO {
return new Spinach(p.remA()); }
Pizzav topAwCO {
return new Spinach(p.topAwC()); }
Pizzav subAbCO {
return new Spinach(p.subAbC()); }
po
Pizzav, Crust, Cheese,
Sa u sage?
we need to change
Olive, Anchoy,
or
4
8
No. When we add variants to the datatypes
we have deined, we don't need to change
what we have.
49
Isn't that neat?
Yes, this is a really lexible way of deining
clsses and methods. Unfortunately, the
more things we want to do with
Pizzavs,
the
more methods we must add.
rue enough. And that means cluttered
50
That would be great, because these
deinitions are painful to the eye. But we
clsses. Is there a better way to express all
don't know of a better way to organize these
this?
deinitions yet.
Don't worry. We are about to discover how
51
Great.
52
We will stick with anchovies.
to make more sense out of such things.
And now you can replace anchovy with
whatever pizza topping you want.
Chapter 3
54
Copyrighted Material
�.�
.
� )
@J� {!� @)��'
D®l���l
Copyrighted Material
Wsn't this lst collection overwhelming?
It sure ws. We deined seven clsses and
each contained three method deinitions.
Could it get worse?
It sure could. For everything we want to do
with
Pizzav,
we must add a method
deinition to each clss.
Because it becomes more and more diicult
Why does that become overwhelming?
to understand the rationale for each of the
methods in a variant and what the
relationship is between methods of the same
name in the diferent variants.
Correct. Let's do something about it. Take a
close look at this visitor clss.
4
These methods look familiar. Have we seen
them before?
class OnlyOnionsv {
boolean jorSkewerO {
return true; }
boolean jorOnion(ShishV s) {
return s.onlyOnionsO; }
boolean jorLamb(ShishV s) {
return false; }
boolean jorTomato(ShishV s) {
return false; }
}
V This superscript is a reminder that the clss s a visitor
clss. Lower superscripts when you enter ths kind
deinition in a ile: OnlyOnionsV.
of
That's right. The major diference is that
Almost. Each of them corresponds to an
onlyOnions
Shishv.
Is
method in one of the
only Onions
va ria nt s
of
they are all in one class, a visitor, whose
name is OnlyOnionsv.
diferent rom OnlyOnionsV?
Come to Our Carousel
The former is used to name methods, the
latter names
Copyrighted Material
a
clss.
57
7
And that's the whole point.
8
We want all the methods in one clss.
•
W hat p o mt?
What methods?
Those methods that would have the same
If we could do that, it would be much esier
name if we placed them into the variants of a
to
dat atype in one clss.
perform .
That's what we
re
10
about to do. We are
un derst and
what action these methods
It's about time.
going to separate the action rom the
datatype.
What is t he
diference between
the method
11
Everything following
return
is the same.
onlyOnions in the Onion variant and t he
method for Onion in t he visitor OnlyOnionsV?
12
Right. W hat is the diference?
followed by
0
for
13
is
and that
OnlyOnionsv is
Yes, that is the diference. Are the other
methods in OnlyOnionsv related to their
that onZyOnions in Onion
forOnion in
followed by (ShishV s).
The diference is
Indeed, they are.
counterparts in the same way?
It is time to discuss the boring part.
The boring part tells us how to make all of
this work .
14
IS
What boring part?
rue, we still don ' t know how to mke
Shishv
and its variants work with this visitor
clss, which contains all the action.
58
Copighed Mateial
Chapter 4
16
Now take a look at this.
{
OnlyOnionsv ooFn
new OnlyOnionsV();
abstract boolean onlyOnions();
abstract
I
class
Shishv
=
}
This is a strange set of deinitions. All the
only Onions
I
methods in the variants look
alike. Each of them uses an instance of
OnlyOnionsv, which is created in the
datatype, to invoke a
for
method with a
matching name.
clss Skewer extends Shishv {
boolean onlyOnionsO {
return ooFn.forSkewerO; }
}
class Onion extends Shi shv {
Shishv s;
Onion(ShishV _s} {
8 = _S; }
boolean oniyOnionsO {
return ooFn.forOnion(s}; }
}
class Lamb extends
Shishv
{
ShishV 8;
Lamb(ShishV
s
=
_8;
_s} {
}
boolen onlyOnionsO {
return ooFn.forLamb(s); }
}
class Tomato extends Shishv {
Shishv s;
Tomato(ShishV _s) {
8 = _s; }
onlyOnionsO {
return ooFn.forTomato(s); }
boolean
}
Come to Our Carousel
Copyrighted Material
59
What does the
forOnion
method in
Onion
17
consume?
s,
That's what "consumption" is all about.
And what does the
Skewer
If "consume" refers to what follows the name
between parentheses, the method consumes
forSkewer
1S
method in
which is the rest of the shish.
Nothing, because a skewer is the bsis of a
shish and therefore hs no ields.
consume?
( ShishV s)
forOnion?
So what does the
deinition of
mean in the
19
It is always the rest of the shish, below the
top layer, which is an onion. In other words,
it is everything but the onion.
Very good. The notation
( ShishV s) means
a Shishv and that
forOnion consumes
between { and }, s stands
that
Explain
20
That makes sense and explains
s.onlyOnionsO·
for that shish.
21
s.onlyOnionsO.
Here are our words:
"s
is a
Shishv,
and therefore
s.onlyOnionsO
determines whether what is below the
onion is also edible by an onion lover."
Explain
22
ooFn.forOnion(s).
You knew we wouldn't let you down:
"ooFn.forOnion
says that we want to use
the method we just described. It consumes
a
Shishv,
and
s
is the
Shishv
that
represents what is below the onion."
23
So what is the value of
new Onion (
new Onion (
new Skewer()))
.onlyOnionsO?
And how do we determine that value with
these new deinitions?
2.
It is still
true.
We start w ith the
Onion,
only Onions
method in
but it immediately uses the
forOnion
method on the rest of the shish.
60
Copyrighted Material
Chapter 4
And what does the
for Onion
method do?
25
It checks whether the rest of this shish is
edible by onion lovers.
26
How does it do that?
27
Isn't that where we started from?
28
Welcome to the carousel.
It uses the method
only Onions on s.
Yes, we're going round and round.
Fortunately, the shish shrinks
s
it goes
around, and when we get to the skewer we
stop.
And then the ride is over and we know that
for this example the answer is
9
2
That's exactly it.
true.
Do we need to remember that we are on a
3D
crousel?
No! Now that we understand how the
separation of data and action works, we only
need to look at the action p art to understand
how things work.
31
Is one example enough?
No, let's look at some of the other actions on
shishes and pizzs.
Let's look at
is Vegetarian
next. Here is the
beginning of the protocol. 1
32
What about it?
abstract class Shishv {
OnlyOnionsv ooFn new OnlyOnionsvO;
IsVegetarianv ivFn new IsVegetarianvO;
abstract boolean only Onions 0;
abstract boolean is Vegetarian 0 ;
}
=
=
1
The Amenean Heitage Dictionay deines protocol s
" (tJ he form of ceremony and etiquette observed by diplomats
and heds of state." For us, a protocol is
an
agreement on
how clsses that speciy a datatype and its variants interact
with clsss that realize functions on that datatype.
Come to Our Carousel
Copyrighted Material
61
Write the rest!
33
We must add two lines to each variant, and
they are almost the same
s
those for
ooFn.
class Skewer extends ShishD {
boolean onlyOnionsO {
return ooFn.forSkewer(); }
boolean is Vegetaian 0 {
return ivFn.forSkewerO ; }
}
clss Onion extends ShishD {
ShishD s;
Onion(ShishV _s} {
s = _s; }
boolean onlyOnionsO {
return ooFn.forOnion(s}; }
boolean is Vegetarian 0 {
eturn ivFn.forOnion(s); }
�
class Lamb extends Shishv {
Sh i shD s;
Lamb(ShishV s} {
s _s; }
_
=
boolen onlyOnionsO {
return ooFn.forLamb(s); }
boolean is Vegetarian 0 {
return ivFn.forLamb(s}; }
}
class Tomato extends Shishv {
Sh i shD s;
Tomato(Shish v _s) {
s = s; }
_
boolean o nlyOnionsO {
return ooFn.forTomato ( s); }
boolean is VegetaianO {
return ivFn.forTomato ( s); }
}
62
Copyrighted Material
Chapter 4
That's why we call this part boring.
3.
rue,
the re ' s very little to think about. It
could be done automatically.
How do we deine the visitor?
35
Does that refer to the clss that contains the
actions?
Yes, that one. Deine the visitor.
36
It is like OnlyOnionsv
forTomato.
except for the method
clss IsVegetarian v {
boolean forSkewerO {
return true; }
boolean forOnion(ShishV s) {
return s. is Vegeta rian (); }
boolean forLamb(ShishV s) {
return false; }
boolean forTomato(ShishV s) {
return s. is Vegetarian(); }
}
Are we moving fst?
37
Yes, but there are only a few interesting
parts. The protocol is always the same and
boring; the visitor is always closely related to
what we saw in ch apter 2.
How about
a
tea break?
38
Instead of cofee?
The Fourth Bit of Advice
hen writing seveal functions for the
same self-referential datatype, use
visitor potocols so that all methods for
a function can be found in a single
class.
Come to Our Carousel
Copyrighted Material
63
Is
39
new
Anchoy(
new Olive(
new Anchoy(
new Cheese(
new Crust()))))
No, it ' s a pizza.
{}
I abstract clss
I clss extends Pi z v { }
Pizzav
Crust
z a
a shish kebab?
clss Cheese extends P izzav {
Pizzav p;
Cheese(PizzaV -p) {
P -Pi }
=
}
class Olive extends
Pizzav p;
Oli ve (P izzaV -p) {
P = Pi }
Pizzav
{
-
}
class Anchoy extends
Pizzav P;
Anchoy(PizzaV -p) {
P -Pi}
Pizzav
{
=
}
clss Sausage extends Pi zza v {
Pi zza v p;
Sausage(PizzaV -p) {
P = -Pi}
}
So
what
do
we do next?
40
We can deine the protocol for the methods
that belong to Pizzav and its extensions:
remA, topAwC,
64
Copyrighted Material
nd
subAbC.
Chapter 4
Great! Here is the
protocol.
ab s ract
t
portion
of the
abstract class PizzaD {
RemAv remFn new R emAv O ;
TopAwCv topFn new TopAwCvO;
SubAbCv subFn = new SubAbCvO;
abstract PizzaD remAO;
abstract PizzaD topAwCO;
abstract PizzaD su bAbCO;
}
=
=
And
41
How innovative! The variants are totally
mindless, now.
class Olive extends PizzaD {
PizzaD p;
Olive(PizzaD -p) {
p -p; }
=
PizzaD remA() {
return remFn.forOlive(p); }
PizzaD topAwCO {
return topFn.forOlive (p); }
PizzaD subAbCO {
return subFn.forOlive (p); }
here are some variants.
class Crust exte nds PizzaD {
PizzaD remA() {
return remFn.forCustO; }
PizzaD t opAwC O {
return topFn.jorCustO; }
PizzaD subAbCO {
return subFn.jorCrustO; }
}
class Cheese extends PizzaD {
PizzaD p;
Cheese(PizzaD -p) {
p = -p; }
PizzaD remAO {
return remFn.jorCheese(p); }
PizzaD topAwCO {
return topFn.jorCheese(p); }
PizzaD su bA bCO {
return subFn.forCheese(p); }
-l
}
class Anc hoy extends Pizzav {
PizzaD p;
Anchovy(PizzaD -p) {
p = -p; }
}
PizzaD remAO {
return remFn.forAnchovy(p); }
PizzaD topAwCO {
return topFn.forAnchovy(p); }
PizzaD s ubA b C ( ) {
return subFn.forAnchovy(p); }
class Sausage extends Pi zzaD {
PizzaD p;
Sausage(PizzaD -p) {
p = -p; }
}
PizzaD
remAO {
return remFn.forSausage(p); }
PizzaD topAwCO {
return topFn.forSausage(p); }
PizzaD subAbCO {
return subFn.forSausage(p); }
Deine the rest.
}
Come to Our Carousel
Copyrighted Material
65
.2
We are all set.
Is it time to deine the visitors that
correspond to the methods
and
43
Oay, here is R e m Av.
Deine TopAwCv.
SubAbCv,
is a piece of cake.
remA, topA wC,
By now, even this is routine.
class TopAwCv {
Pizzav for CrustO {
return new CrustOj }
Pizzav for Cheese(PizzaV p) {
return new Cheese(p.topAw CO)j }
Pizzav forOlive(PizzaV p) {
return new Olive(p.topAwC())j }
Pizzav forAnchovy(PizzaV p) {
return
new Cheese(
new Anchoy(p.topAw C()))j }
Pizzav forSausage(PizzaV p) {
return new Sausage(p.topAwC()); }
}
class RemAv {
PizzaD forCrustO {
return new C rust O j }
PizzaD forCheese(PizzaD p) {
return new Cheese(p.remAO); }
PizzaD forOlive(PizzaD p) {
return new Olive(p.remA())j }
Pizzav forAnchovy(PizzaV p) {
return p. remAOj }
PizzaD forSausage(PizzaD p) {
return new Sausage(p.remA())j }
}
The lst one,
subAbC?
••
And we thought we were working with a
pizza pie.
class SubAbCv {
Pizzav forCrustO {
return new CrustOj }
Pizzav for Cheese(PizzaD p) {
return new Cheese(p.subAbC()); }
Pizzav forOlive(PizzaV p) {
return new Olive(p.subAbC())j }
Pizzav forAnchovy(PizzaD p) {
return new Cheese(p.subAbC()); }
PizzaD forSausage(PizzaV p) {
return new Sausage(p.subAbC())j }
}
66
Copyrighted Material
Chapter 4
�o
JJ@S� �f��
P��@Yrr�Il� ) )@
J
.' 7
7 .
-
�
7
--
�
Copyrighted Material
Have we seen this kind of deinition before?l
1
What? More pizza!
abstract class PieD {
}
-(
)-
Pie
�---�
clss Bot extends PieD {
}
-(
)-
Bot
class Top extends PieD {
Object t;
PieD r;
Top(Object _t,PieD _r) {
t _t;
r
}
=
=
_r;
-(
}
)-
Top
�----�
1 Better nms for these clsses would be PizzPieD,
nd Topping, rspetively.
Yes, still more pizza,
but this
What kind of toppings
inds of pizza?
can
Bottom
one is diferent.
we put on these
Yes, it includes only one variant for adding
toppings to a pizza, and toppings are Objects.
Any kind, because Object is the clss of all
objects. Here are some ish toppings.
abstract clss
Fi shD
{}
class Anchoy extends
Fi shD
{}
class Salmon extends FishD {}
class Tuna extends FishD {}
Objects
Are People, Too
Copyrighted Material
69
Nice datatype. Is
new Top(new AnchoyO,
new Top(new TunaO ,
new Top(new An chovyO ,
new Bot())))
a pizza pie?
It is a pizza pie, and so is
new Top(new TunaO,
new Top(new Integer(42) ,
new Top(new AnchoyO,
new Top(new Integer(5),
new Bot())))).
What is the value of
new Top(new Sa lmo n O,
new Top(new AnchoyO,
new Top(new TunaO,
new Top(new AnchoyO,
new Bot()))))
.remAO?
It is this ishy pizza pie:
new Top(new SalmonO ,
new Top(new TunaO,
new Bot())).
Is it true that the value of
new Top(new Sa lmonO ,
new Top(new T u naO ,
new BotO))
Yes. The pizza that comes out is the same
the one that goes in, because there are no
anchovies on that pizza.
s
.remAO
is
new Top(new SalmonO,
new Top(new T unaO ,
new Bot()))?
7
Does remA belong to PieD?
Deine the protocol for RemAv. We provide
the abstract part.
RemAV aFn = new RemAVOj
abstract PieD remAO;
Yes, and it produces pizza pies.
This is esy by now.
PieD remAO {
return aFn.forBotOj }
Bot
Pie
PieD remAO {
return raFn.forTop(t,r)j }
Top
70
Copyrighted Material
Chapter 5
9
Great. Isn't that esy?
What part of this exercise
datatype to datatype?
difers rom
10
Esy and boring.
Determining how many ields a variant
contains. In our cse, we
11
Anything else?
12
13
Let's deine the visitor Re m A v.
clss RemA v {
PieD jorBotO {
return
;}
PieD jorTop(Object t , PieD r) {
if (new AnchoYO.equals(t))
return
else
return
; }
__
14
does
Objects Are People, Too
Because these are the ields of
is
Top.
Here are some guesses.
We guess:
"This produces the value of either exr2 or
is determined
to be
true
or
eprl
false,
respectively. "
15
We could guess:
"This expression determines whether
equal to
mean?
depends on what
raFn.forBot
aFn.forTop by ( t , r) .
exr3, depending on whether or not
And what does
new AnchovyO. equals ( t)
yet. It
and
}
}
Not
0
clss RemAv {
PieD jorBotO {
return new BotO ; }
PieD jorTop(Object t,PieD r) {
if (new AnchovyO.equals(t))
return r.emAO;
else
return new Top(t,r.remA()); }
____
Great uesses! What
if ( exprl)
return expr2;
else
return expr3;
mean?
zero and two.
No, rom that we now that
followed by
Why (t,r)?
had
equals
means.
16
t
is
new AnchovyO."
What?
Copyrighted Material
71
What is the value of
new Anchovy().equals(new Anchovy())?
Yes! And what is the value of
new AnchovyO.equals(new Tuna())?
The clss Object contains a method called
equals. This method compares one Object to
another, and it always returns false.l
17
IS
19
The "Not
yet."
implies that the value is false.
false,
because no anchovy is a tuna.
If we know that equals's answer is always
false, why bother to use it?
1 Not always, We explain the correct answer in chapter 10.
We must deine it anewl for all clsses whose
instances we wish to compare.
20
Oay. How?
1 In Java, redeining a method is called ·'overriding."
For Fishv and its variants it works like this.
I abstract class Fishv {}
21
Assuming that
(0 instanceof Tuna)
is true when 0 is an instance of Tuna, these
method deinitions are obvious.
class Anchovy extends Fishv {
publicI boolean equals(Object 0 ) {
return ( 0 instanceof Anchovy); }
}
class Salmon extends Fishv {
public boolean equals(Object 0 ) {
return (0 instanceof Salmon); }
}
class Tuna extends Fishv {
public boolean equals(Object 0) {
return (0 instanceof Tuna); }
}
72
I The clss Object is deined in a seprate pcage, called
java.lng.Object. Overriding methods that reside in other
packages requires the word public.
Copyrighted Material
Chapter 5
Aren't they? Is every value constructed with
new an instance of Object?
If
class A extends B, is every value created
by new A( ... ) n instance of clss B?
22
23
24
Now, what is the value of
new Anchovy(). equals ( new Anchovy())?
Yet the value
25
of
new AnchovyO.equals(new Tuna())
is still false.
Could we have
equals?
written
RemAv without using
26
Yes. Every such value is an Object, because
every clss extends Object directly or
indirectly.
Yes, and of the
on.
clss
that B extends and so
true,
because new AnchovyO
Anchoy.
is
an instance of
Of course, because an anchovy is never a
tuna.
Absolutely, instanceof is enough.
class RemA v {
Piev JorBotO {
return new BotO; }
Piev JorTop(Object t,Piev r) {
if (t instanceof Anchovy)
return r.remA()j
else
return new Top(t,r.remAO); }
}
Why haven't we deined it
Esy, because we want to generalize RemA v
so that it works for any kind of ish topping.
What are good names for the more general
methods and visitor?
Objects Are People, Too
27
28
this
way?
We can do that, but when e use the
methods of the more general visitor, we need
to say which kind of ish we want to remove.
How about remFish and Rem Fish v?
Copyihted Mateial
73
29
How do we use e
mFish?
Add the protocol for RemFishv. We designed
the abstract portion.
30
We give it a Fishv.
The rest is routine.
Piev remFish(FishV f) {
return rfFn.forBot(f); }
RemFishV rfFn new RemFishvO;
abstract Piev remFish(FishV f);
=
Bot
Pie
Piev emFish(FishV f) {
return rfFn.forTop(t,r, f); }
Top
Where do (f) and (t,r,J) come from?
Let's deine RemFishv and its two methods.
31
3.
The f stands for the Fish v we wnt to
remove in both cses. The t and the r re
the ields of Top; Bot doesn't have any.
Instead of compring the top layer t of the
pizza to Anchoy, we now determine whether
it equals the Fishv f, which is the additional
value consumed by the method.
class RemFishv {
PieV forBot(FishV f) {
return new BotO; }
PieV jorTop(Object t,PieV r,FishV f) {
if (t. equals ( t))
return r.emFish(f);
else
return new Top(t,r.remish(f)); }
}
If we add another kind of ish to our
datatype, what would happen to the
deinition of RemFishv?
74
33
Nothing, we just have to remember to add
equals to the new variant.
Copighted Mateial
Chapter 5
Let's try it out with a short example:
new Top(new AnchovyO,
new Bot())
.remFish(new Anchovy()).
Yes. What values does forTop consume?
5
3
3
And now?
6
37
So?
38
What is the value of
new BotO
.remFish(new Anchovy())?
What does forBot in
34
Rem Fish v
All clear?
Objects Are People, Too
produce?
39
40
The object is a topping, so we use forTop
rom Rem Fishv.
It consumes three values: new AnchovyO,
which is t, the top-most layer of the pizza;
new BotO, which is r, the rest of the pizza;
and new AnchovyO, which is f, the Fishv to
be removed.
Now we need to determine the value of
if (f. equals(t))
return r.remFish(f);
else
return new Top(t,r.remFish(f));
where t, r, and f stand for the values just
mentioned.
Given what f and t stand for, f.equals(t) is
true. Hence, we must determine the value of
r. remFish(f) .
It is the same s
forBot(f),
where f is new AnchovyO.
It produces new BotO, no matter what f is.
Ready to move on, ater snack time.
Copyrighted Material
75
41
Does
new Top(new Integer(2),
new Top(new Integer(3),
new Top(new Integer(2),
new Bot())))
. remlnt(new Integer(3))
look familiar?
42
What does remlnt do?
Who deined equals
for
43
Integer?
44
Deine the visitor RemlntV
Yes, it looks like what we just
evaluated.
It
removes Integers rom pizza pies just
remFish removes ish from pizza pies .
s
The Machine decided
new Integer(O).equals(new Integer(O))
to be true, and the rest ws obvious.
Wonderful! We do the interesting thing irst.
This visitor is almost identical to Rem Fishv
We just need to change the type of what the
two methods consume.
class RemlntV {
Piev forBot(lnteger i) {
return new BotO; }
Piev JorTop(Object t,Piev r,lnteger i) {
if (i.equals(t))
return r.remlnt(i);
else
return new Top(t,r.remlnt(i)); }
-
}
Does it matter that
not J?
this
Where is the protocol?
76
deinit ion uses i and
45
46
No, i is just a better name than J, no other
reson. As long s we do such substitutions
systematically, we are just ine.
It
is so simple, let's save it
Copyrighted Material
for
later.
Chapter 5
Cn we remove Integers rom PieDs?
Cn we remove FishD
rom
48
PieDs?
49
Let's combine the two deinitions.
Yes.
Yes, and we use nearly identical deinitions.
If we use
Object
instead of the underlined
Integer above, everything works out.
50
hy?
Just
47
Because
an
51
do it!
everything
constructed
w
i th
new is
Object.
It's done.
clss Re m v {
PieD jorBot( Object 0 ) {
return new Bot(); }
PieD jorTop(Object t,PieD r,Object 0 ) {
if (o.equals(t))
return r.rem(o);
-
else
return
new Top(i,r.rem(o)); }
}
Should we do the protocol
for
all these
52 Now?
isitors?
You never now when
it might
be useful,
53
even if it does not contain any interesting
Let's just consider
Rem v
information.
Why not
Remlntv?
Rem Fishv
and RemA v and
Objects Are People, Too
54
They are unnecessary once
Copyrighted Material
we have Rem v
77
Here is the abstract portion of
abstract class
Piev.
55
And here are the pieces for
and Top
.
Bot extends Piev {
Piev em(Object 0) {
return remFn.forBot(o); }
clss
Piev {
Rem v emFn new Rem v 0 j
Piev rem(Object 0);
=
}
Bot
abstract
}
Piev {
Object t;
Piev r;
Top(Object _t,Piev _r) {
t
_t;
r _r; }
clss Top extends
=
=
Piev rem (Object 0) {
return remFn.forTop(t,r,o); }
}
Let's remove some things rom pizza pies:
56
57
And how about
new Top(new
Works like a charm with the same result
s
before.
Integer(2),
new Top(new Integer(3),
new Top(new Integer(2),
new Bot())))
. rem(new Integer(3)).
new Top(new
Ditto.
AnchoyO,
new BotO)
.rem(new Anchoy())?
Next:
AnchoyO,
new Top(new Integer(3),
new Top(new ZeroO,
new Bot())))
. rem(new Integer(3)).
new Top(new
78
58
No problem. This, too, removes
3
and leaves
the other layers alone:
AnchoyO,
ZeroO,
Bot())) .
new Top(new
new Top(new
new
Copyrighted Material
Chapter
5
59
What is the value of
new Top(new AnchovyO,
new Top ( new Integer(3) ,
new Top(new ZeroO,
new 8ot())))
. rem(new Zero())?
60
What's wrong with that?
61
And why didn't it?
62
Always?
Here is the version of Numv ( including
OneMoreThan) with its own equals. Deine
the new Zero variant.
[ abstract class
Numv
{}
class OneMoreThan extends
Numv predecessor;
OneMoreThan(NumV -p) {
predecessor _Pi }
Numv
{
=
public boolean equals(Object 0 ) {
if ( 0 instanceof OneMoreThan)
return
predecessor
. equals (
((OneMoreThan)o)l.predecessor);
else
return false; }
}
Objects Are People, Too
63
Oops. The answer is
new Top(new AnchovyO,
new Top(new Integer(3),
new Top(new ZeroO,
new 8ot()))) .
We expected it to remove new ZeroO from
the pizza.
Because equals for Numvs uses Object's
equals, which always produces false-s we
discussed above when we introduced equals.
Unless we deine it anew for those clsses
whose instances we wish to compare.
Adding equals to Zero is esy. We use
instanceof to determine whether the
consumed value is a new ZeroO.
clss Zero extends Numv {
public boolean equals(Object 0 ) {
return (0 instanceof Zero); }
}
But what is the underlining of
((OneMoreThan) 0 )
about? Wouldn't it have been suicient to
write o.predecessor?
1 In Java, this is called (downward) csting, because
OneMorehn extends ND.
Copyrighted Material
79
64
No. What is the type of o?
65
So what is o.predecessor?
Correct. What do we know ater if hs
determined that
(0 instanceof OneMoreThan)
is true?
Precisely. So what does ((OneMoreThan)o)
do?
What is ((OneMoreThan) o ) s type?
'
Are
67
6S
69
0
and ((OneMoreThan)o)
interchangeable?
Is this complicated?
Did you also notice the
predecessor
. equals (
(( OneMoreTha n) 0). predecessor)
in equals for OneMoreThan?
The irst one, predecessor, refers to the
predecessor ield of the instance of
OneMoreThan on which we are using equals.
And that ield might not be a OneMoreThan.
80
66
Object, according to
(Object 0 ) ,
which is what declares the type of o.
Nonsense.
We know that o's type is Object
is an instance of OneMoreThan.
and
that it
It converts the type of 0 rom Object to
OneMore Th a n .
Its type is OneMoreThan, and now it makes
sense to write
((OneMoreThan) o).predecessor.
The underlying object is the same. But no,
the two expressions are not interchangeable,
because the former's type is Object, wheres
the latter's is OneMoreThan.
70
Someone hs been drinking too much cofee.
71
How do the two uses of predecessor difer?
72
So the second one,
((OneMoreThan) o).predecessor,
refers to the predecessor ield of the instance
of OneMoreThan consumed by equals.
Copyrighted Material
Chapter
5
73
Yes. Are these two objects equal?
If they are similar1 to the same int, they are
equal. But most of the time, they are not.
1 Check chapter 1 for usimilar."
74
Time for lunch?
75
Did you have a good lunch break?
76
Now what is the value of
new Top(new AnchovyO,
new Top(new I
nteger(3),
new Top(new Z eroO
new Bot())))
. rem(new Z ero())?
,
That's just in time.
Yes, thank you.
Now we get
new Top(new AnchovyO,
new Top(new Integer(3),
new Bot() ))
which is precisely what we want.
,
And why?
77
Do we always add equals to a clss?
78
No, only if we need it.
79
Yes, we do.
Do we need equals when we want to
substitute one item for another on a pizza
pie?
80
What is the value of
new Top(new AnchovyO,
new Top(new TunaO,
new Top(new AnchovyO,
new Bot())))
.substFish(new SalmonO,
new Anchovy())?
What kind of values does substFish consume?
Objects Are People, Too
81
Because equals now knows how to compare
NumDs.
It is the same pizza pie with all the anchovies
replaced by salmon:
new Top(new SalmonO,
new Top(new TunaO,
new Top(new SalmonO,
new Bot()))).
It consumes two ish and works on PieDs.
Copyrighted Material
81
82
And what does it produce?
83
What is the value of
new Top(new I
nteger(3),
new Top(new Integer(2),
new Top(new Integer(3),
new 80t())))
.substInt(new Integer(5),
new Integer(3))?
What kind of values does substInt consume?
8.
85
And what does it produce?
86
We can deine SubstFishv.
class SubstFishv {
PieD JorBot (FishD n,FishD 0) {
return new 80tO; }
PieD JorTop(Object t,
PieD r,
FishD n,
FishD 0) {
if (0. equals (t))
return new Top(n,r.substFish(n,o));
else
return new Top(t,r.substFish(n,o)); }
Deine Substlntv.
82
It is the same pizza pie with all 3s replaced
by 5s:
new Top(new Integer(5),
new Top(new Integer(2),
new Top(new Integer(5),
new 80t()))).
It consumes two Integers and works on PieDs.
It always produces a PieD
To get rom SubstFishv to SubstlntV, we just
need to substitute FishD by Integer
everwhere and 'Fish" by "Int" in the clss
and method names.
clss SubstlntV {
PieD JorBot(lnteger n,lnteger 0) {
return new 80tO; }
PieD JorTop(Object t,
PieD r,
Integer n,
Integer 0) {
if (o.equals(t))
return new Top(n,r.substInt(n,o));
else
return new Top(t,r.substInt(n,o)); }
}
Did we forget the boring parts?
It always produces a PieD.
}
87
Yes, because there is obviously a more
general version like Rem v
Copyrighted Material
Chapter
5
Yes, we
call it Substv.
88
D eine it.
We
substitute
Object for Fishv
and
Integer.
class SubstV {
Piev JorBot(Object n,Object 0) {
return new BotOj }
Piev JorTop(Object t,
Piev r,
Object n,
Object 0) {
if (0. equals ( t))
return new Top(n,r.subst(n,o))j
else
return new Top(t,r.subst(n,o))j }
}
Now it is time to add the protocol for SubstV
to Piev Here are the variants.
89
The
abstract part is obvious.
abstract class Piev {
Rem v remFn new Rem v 0 j
SubstV substFn new SubstVOj
abstract Piev rem(Object 0);
abstract Piev subst(Object n,Object 0);
}
class Bot extends Piev {
Piev rem(Object 0) {
return emFn.forBot ( 0); }
Piev subst (Object n,Object 0) {
return substFn.forBot(n,o)j }
=
=
}
class Top extends Piev {
Object tj
Piev r;
Top(Object _t,Piev s) {
t _tj
r = _rj }
=
P i ev em (Object 0) {
return remFn.forTop(t,r,o)j }
Piev subst(Object n,Object 0) {
return substFn.forTop(t,r, n, o)j }
}
90
So?
Objects Are People,
Too
That
ws some heavy liting.
Copighed Mateial
83
Copyrighted Material
1
Are protocols truly boring?
But, of course they are not. We just didn't
•
We acted s If they were.
Okay, here are the variants again.
want to spend much time on them. Let's
take a closer look at the lst one we deined
class Bot extends Piev {
Piev rem(Object 0) {
return remFn.forBot(0); }
Piev subst(Object n,Object 0) {
return substFn.forBot(n,o); }
in the previous chapter.
abstract class
Piev {
Rem v remFn new Rem v 0;
SubstV substFn new SubstVO;
abstract Piev em(Object 0);
abstract Piev subst(Object n,Object 0);
=
=
}
}
class
Top extends Piev {
Object t;
Piev r;
Top(Object _t,Piev _r) {
t
_t;
r _r; }
=
=
}
What is the diference between
subst
in
and
in the
Bot
The irst one consumes one
Object,
the
second one consumes two.
What is the diference between
subst
em
Piev?
Piev em(Object 0) {
return remFn.jorTop(t,r,o); }
Piev subst(Object n,Object 0) {
return substFn.jorTop(t,r,n, 0) ; }
rem
and
rem
forBot service from
Object it
consumes; subst sks for the forBot service
rom substFn and hands over the two Objects
Simple:
remFn
variant?
sks for the
and hands over the
it consumes.
What is the diference between
subst
in the
Top
variant?
rem
and
rem sks for the forTop service
remFn and hands over the ield values
and the Object it consumes; subst sks for
the for Top service rom substFn and hands
over the ield values and the two Objects it
Simpler:
rom
consumes.
Boring Protocols
Copyrighted Material
85
And that is all there is to the methods in the
Let's not
cre ate
remFn
and substFn in the
datatype.
{
rem(Rem v remFn,
Object 0);
sub s t ( Subst V substFn,
Object n,
Object 0);
abstract class PieD
abstract PieD
abstract PieD
6
But
remFn
and substFn deined in the
datatype are still a bit mysterious.
variants of a protocol.
This looks like an obvious modiication. The
new rem and subst now consume a remFn
substFn , respectively. C an they still
ind forBot and forTop, their corresponding
and a
carousel partners?
}
Yes, it is a straightforward trade-of. Instead
The deinition of the datatype says that they
of adding
are a
And
every
and
a
remFn ield and
a
to the datatype, we now have
substFn ield
rem or subst
consume such values. W hat kind of values
are consumed
by rem
and
subst?
In the same manner . We just need to change
Here is how it changes Top.
class Top extends PieD
Object
PieD r;
t
=
=
_
each concrete method's description of what it
{
consumes. The rest remains the same.
t;
t;
_r;
_
r
PieD
) {
}
rem(Rem v remFn,
Object 0) {
return remFn . fo r Top( t , r , o ) ; }
PieD subst(Substv substFn,
Object n,
Object 0) {
return substFn.forTop(t,r,n,o); }
PieD
}
Bot extends PieD {
rem(Rem v remFn,
Object 0) {
return remFn.forBot( 0); }
PieD subst ( Subst V substFn,
Object n,
Object 0) {
return substFn.forBot(n,o); }
class
Top(Object _t,PieD
r
so
Rem v and a Substv , respectively.
Remv deines forBot and f o r Top ,
does every Substv .
How does it afect
}
Bot?
86
Copyighted Mateial
Chapter 6
That's right. Nothing else changes in the
variants. Instead of relying
on
0
1
We still have some work to do.
ields of the
datatype, we use what is consumed.
11
Like what?
Consuming
12
Where are they used?
In
an
extr a value here also afects
met hods
how the
Remv
and
rem
SubstV,
for example.
Yes. Here is
13
Rem v .
I}
SubstV
subst
are used.
the interesting parts ,
That takes all the fun out of it.
class SubstV {
PieD JorBot(Object n,
Object 0 ) {
return new BotO; }
PieD JorTop(Object t,
PieD r,
Object n,
Object 0) {
if (0. equals ( t))
return
new Top(n,r.subst(this,n,o));
else
return
new Top(t,r.subst(this,n,o)); }
class Remv {
PieD JorBot{ Object 0 ) {
return new BotO; }
PieD JorTop{Object t,
PieD r,
Object 0 ) {
if (0. equals ( t))
return r. rem (this, 0 );
else
return new Top(t,r.rem(this,o)); }
,
Modiy
and
accordingly.
}
What is
this
1
all about?
Understanding is more diicult. The word
this
4
15
Yes, what about it. Copying is esy.
Which object ?
refers to the object itself.
How did we get here?
16
The p rot ocol is that
for the
JorBot
remFn,
Boring Protocols
Copyrighted Material
and
rem in Bot and Top sks
JorTop methods of
respectively.
87
17
How does that happen?
It happens with
re�Cn·for3ot( ... )
and
re�Cn·forTop( ... ) ,
respectively.
for3ot and forTop
object e�Cn s this.
Correct. And now
refer to the
can
18
Oh, so inside the methods of
Rem v, this
Rem v
stands for precisely that instance of
that allowed us to use those methods in the
irst place. And that must mean that when
we use
r.re�(this, ... )
in
forTop,
it tells
e�
to use the same instance over again.
19
That's it. ricky?
20
Why?
21
What is the value of
new Top ( new AnchovyO ,
Not really, just self-referential.
Rem v,
Because
this
what
need to complete the job.
e
is a
and it is exactly
We did the same example in the preceding
chapter, and the result remains the same.
new Top ( new
Integer(3),
new Top ( new Z e roO ,
new BotO)))
.re� ( new RemvO,
new Z e ro ))?
And how does the underlined part relate to
22
what we did there?
What is the value of
new Top ( new
Integer(3),
new Top ( new Integer(2),
new Top ( new Integer(3),
new Bot())))
.subst ( new SubstVO,
new Integer(5),
new Integer(3))?
88
to the
23
Rem v object, which
emFn in the old Piev
It creates a
corresponds
We did the same example in the preceding
chapter, and the result remains the same.
Copyrighted Material
Chapter 6
And how does the underlined part relate to
24
what we did there?
25
So what is the underlined part about?
SubstV obj ect, which corresponds
remFn in the old PieD.
It creates a
to the
We changed the methods in
PieD,
which
means that we must also change how it is
used.
26
Ready for the next protocol?
27
How about some ice cream?
Let's grab a quick snack.
Cappuccino crunch sounds great. The more
cofee, the better.
Take a look at
Substv.
subst
in
Top and
at
forTop
in
28
What happens to the values that
Nothing really. They get handed back and
forth, though
forTop
compares
0
to
t.
they consume?
Is the handing back and forth necessary?
Here is a way to deine
SubstV
that avoids the
29
30
We don't know any better way, yet.
Wow. This visitor hs two ields.
1
handing back and forth of these extra values.
clss Subst v {
Object n;
Object 0;
SubstV(Object _n,Object _0) {
n = _n;
0= _0; }
}
PieD forBotO {
return new BotO; }
PieD forTop(Object t,PieD r) {
if (0. equals ( t))
return new Top(n,r.subst(this));
else
return new Top(t,r.subst(this)); }
Boring Protocols
1 In functional programming, a visitor with ields is called a
closure (or a higher-order function), which would be the
result of applying a curried version of 5ubst.
Copyrighted Material
89
31
How do we create a Substv?
What does that
We use
new SubstV(new Integer(5),
new I nteger(3) ).
32
do?
It creates a
Substv
whose methods know how
new Integer(5) for all
of new Integer(3) in Piev
to substitute
occurrences
How do the methods know that without
33
The values have now become ields
of the
object to which the methods belong.
They no longer need to be consumed.
SubstV
consuming more values?
Oay, so how wou ld we substitute all
new Integer(3) with new Integer(5)
new Top(new Integer(3),
new Top(new Integer(2),
new Top(new Integer(3),
new Bot O )) )?
34
We write
new Top(new Integer(3),
new Top(new Integer(2),
new Top(new Integer(3),
new Bot())))
.subst(new SubstV(
new Integer(5),
in
new Integer(3»).
And if we want to
new Integer(2)
35
su s
with
b titute all
new Integer(7)
same pie?
Does all that mean we have to change the
protocol,
too?
We write
new Top(new Integer(3),
new Top(new Integer(2),
new Top(new Integer(3),
new Bot())))
.subst(new SubstV(
new Integer(7),
new Integer(2»).
in the
36
Of course, because the methods subst in the
Bot and Top variants consume only one value
now.
90
Copighted Mateial
Chapter 6
That's right. Here are the datatype and its
Bot
variant. Deine the
37
Top variant.
Top variant,
t and r.
In the
both
we still need to hand over
class Top extends PieD {
Object t;
abstract class PieD {
abstract PieD rem(RemV remFn);
abstract PieD subst(SubstV substFn);
PieD r;
Top( Object _t,PieD
t _t;
r
-r'}
,
}
_r
) {
=
=
class Bot extends PieD {
PieD rem(RemV remFn) {
return remFn-forBotO; }
PieD subst(Subst V substFn) {
return substFn-forBotO; }
}
}
38
Is there anything else missing?
PieD rem(Rem V remFn) {
return remFn-forTop(t,r); }
PieD subst(Substv substFn) {
return substFn-forTop(t,r); }
We haven't deined
Rem v
for this new
protocoL But it is simple and hardly worth
our attention.
What is the diference between
subst
in
in
and
39
Bot?
Not much. The name of the respective values
they consume and the corresponding types.
What is the diference between
subst
rem
rem
and
40
Top?
Not much. The name of the respective values
they consume and the corresponding types.
"
Can we eliminate the diferences?
It is esy to make them use the same names.
It doesn't matter whether
rem
is deined
s
it is or s
PieD rem(RemV substFn ) {
return substFn-forTop(t,r); }.
rue, because
substFn
is just a name for a
value we don't know yet. But how can we
make the types the same?
42
Both
Remv
and
SubstV
are visitors that
contain the same method names and those
methods consume and produce the same
types of values. We can think of them s
extensions of a common
Boring Protocols
Copyrighted Material
abstract class.
91
43
Yes! Do it!
Here it is.
abstract class PieV i sitorD {
abstract PieD JorBotO;
abstract PieD JorTop(Object t,PieD r);
}
Great job, except that we will use
interface
44
Okay, that doesn't seem to be a great
interface
abstract class?
diference. Can a clss extend an
for speciying visitors like these.
the way it
PieVisitoI {
PieD forBotO;
PieD forTop(Object t,PieD r);
extends
an
interface
}
I This superscript is a reminder that the name refers to an
interface. Lower superscripts when you enter this kind of
deinition in a ile: PieVisitorI.
No. A clss
implements
an
interface;
it
45
Fine.
does not extend it.
Now that we have an interface that describes
the type of the values consumed by
subst,
rem
46
Yes, we can. Assuming we can use
interfaces
and
can we make their deinitions even
like
abstract classes, we
can
write
PieD rem ( PieV i sitorI pvFn) {
return pvFn.forTop(t,r); }
more similar?
and
PieD subst(PieVisitoI pvFn) {
return pvFn.forTop( t,r); }
in Top.
Correct. What is the diference between
and
subst,
rem
47
There isn't any. We can use the same name
for both,
now?
s
long
s
we remember to use
whenever we would have used
What is a good name for this method?
48
em
or
it
subst.
The method accepts a visitor and ss for its
services, so we call it
92
Copyrighted Material
accept.
Chapter 6
And what is a better name for
pvFn?
Now we can simpliy the protocol. Here is
the new
49
50
Here we go.
abstract class PieD {
abstract PieD accept(PieVisitorI ask);
}
_
}
because we sk for services.
Remv .
class Rem v implements PieVisitor {
Object 0;
RemV(Object 0) {
0=
ask,
Esy:
_
0; }
class Bot extends PieD {
PieD acept(PieVisitor ask) {
return ask.forBotO; }
public PieD forBotO {
return new BotO; }
public PieD forTop(Object t,PieD r) {
if ( 0. equals ( t))
return r.accept(this);
else
return new Top (t,r.accept(this)); }
}
clss Top extends PieD {
Object t;
PieD r;
Top (Object _t,PieD _r) {
t
t;
r = _r; }
=
Supply the protocol.
_
PieD accept(PieVisitor ask) {
return ask.jorTop(t,r); }
}
Did you notice the two underlined
occurrences of
When we deine a
interface,
public to the
an
51
Yes, what about them?
52
Why?
53
Looks weird, but let's move on.
public?
class
that
impIements
we need to add the word
let of the method deinitions.
It's a way to say that these are the methods
that satisy the obligations imposed by the
interface.
Correct. They are just icing.
Boring Protocols
54
Okay, we still won't forget them.
Copyrighted Material
93
Now deine the new
55
Substv.
Here it is.
clss SubstV implements PieVisitorI {
Object n;
Object 0;
SubstV(Object _n,Object _0) {
public PieD JorBotO {
return new Bot() ; }
public PieD JorTop(Object t,PieD r) {
if (0. equals(t))
return
new Top (n,r.accept(this));
else
return
new Top (t,r.accept(this)); }
}
PieVisito�
PieD, Bot, Top , Remv,
Draw a picture of the interface
and all the clsses:
and
56
Here is our picture.
Substv.
accept
-
Why is there is a line, not an arrow, from
SubstV
to
57
PieVisito�?
The
SubstV
it doesn't
visitor
extend
PieV i sito�
implements P ieVisito�,
it. Arrows mean "extends,"
lines mean "implements."
And the dshed line?
58
It tells us the name of the method that
connects the datatype to the visitors.
94
Chapter 6
Copyrighted Material
What is the value of
new Top (new AnchovyO,
new Top(new TunaO,
new Top(new AnchovyO,
new Top(new TunaO,
new Top(new AnchovyO,
new Bot())))))
. accept(new LtdSubstv (2,
new SalmonO,
new Anchovy()))?
Explain what
1
A
LtdSubstv
produces.1
59
new Top(new Salmon(),
new Top( new Tuna O ,
new Top (new SalmonO,
new Top(new TunaO,
new Top(new AnchovyO,
new Bot()))))) .
60
pie by another
s
many times
by the irst value consumed by
we pronounce it.
LtdSubstv
The methods of LtdSubstV replace one ish on
a
better name is LimitedSubstitutionV, and that is how
Good. Deine
Esy:
61
s
speciied
LtdSubstV
That's esy. We have such a lexible protocol
that we only need to deine the essence now.
class LtdSubstV implements PieVisitorL {
int Cj
Object nj
Object OJ
LtdSubstv (int _c,Object _n,Object _0) {
C
n
=
=
0=
}
Boring Potocols
_Cj
_nj
_OJ}
public PieD jorBotO {
return new Bot O j }
public PieD jorTop(Object t,PieD r) {
if(c == 0)
return new To p(t , r ) j
else
if (o.equals(t))
return
new Top(n,r.accept(this))j
else
return
new Top(t,r.accept(this))j }
Copyrighted Material
95
62
W hat is the value of
new Top(new AnchovyO,
new Top(new TunaO,
new Top(new AnchovyO,
new Top(new TunaO,
new Top(new AnchovyO,
new Bot())))))
accept (new LtdSubstV(2,
new SalmonO,
new Anchovy()))?
new Top(new SalmonO,
new Top(new Tun a O ,
new Top(new SalmonO,
new Top(new Tu naO
new Top(new SalmonO,
new Bot()))))).
,
.
63
How come?
Why doesn't
c
64
ever change?
Oops, there are too few anchovies on this
pizza pie:
Because
c,
the counting ield, never changes.
Because this, the
LtdSubstV
that performs
the substitutions, never changes.
65
Can we ix this?
We can't change this, but we can replace
this with a new
LtdSubstv
that relects the
change.
If
c
stands for the current count, how do we
create a
LtdSubstV
that shows that we have
just substituted one ish by another.
66
Simple, we use
new LtdSubstV(c
-
1,n,0)
in place of this.
The Sixth Bit of
Advice
hen the additional consumed values
change for a self-referential use of a
visitor, don't forget to ceate a new
visitor.
96
Chapter 6
Copyrighted Material
Deine the new and
improved version of
67
LtdSubstv.
Voila.
clss LtdSubstV implements PieVisitorI {
int C;
Object n;
Object 0;
LtdSubst v (int _c,Object _n,Object _0) {
c
_c;
n = _n;
o=-Dj }
=
public PieD fo rE otO {
return new BotO; }
public PieD forTop(Object t,PieD r) {
if (c == 0)
return new Top(t,r);
else
if ( 0. equals (t) )
return
new Top(n,
r.accept(
new LtdSubstV(c
l,n,o)));
else
return
new Top(t,
r.accept(
this)); }
-
}
68
How does
replaces
this
c
occurrences of
°
by
n
in a pizza
pie, and the other one replaces only
difer rom
c
-
1 of
them.
new LtdSubstV(c -l,n,o)?
How do you feel about protocols now?
Boring Protocols
They are two diferent LtdSubstVs. One
69
They are exciting. Let's do more.
Copyrighted Material
97
aterial
Copyighted M
1
Is
new Flat(new AppleO,
new Flat(new PeachO,
new Bud()))
a lat TreeD?
2
Is
new Flat(new Pea rO
new Bud())
a lat TreeD?
,
And how about
new Split(
new BudO,
new Flat(new FigO,
new Split(
new BudO,
new Bud())))?
Here is one more example:
new Split(
new Split(
new BudO,
new Flat(new LemonO,
new Bud())),
new Flat(new FigO,
new Split(
new BudO,
new Bud()))).
I s it lat?
TreeD.
No, it is split, so it can't be lat.
4
No, it isn't lat either.
the diference between lat trees and split
trees obvious now?
OhMy!
Yes, it is also a lat
3
Unless there is anything else to TreeD, it's
totally clear.
Is
Good. Then let's move on.
Yes.
6
Okay, let's.
Copyrighted Material
99
Here are some fruits.
It does not difer too much from what we
I abstract class
have seen before.
FruitV
{}
I abstract class
I class Bud extends
Treev
class Peach extends FruitV {
public boolean equals(Object 0) {
return ( 0 instanceof Peach); }
}
class
class Apple extends FruitV {
public boolean equals(Object 0 ) {
return ( 0 instanceof Apple); }
}
class Pear extends FruitV {
public boolean equals(Object 0 ) {
return ( 0 instanceof Pear); }
}
class Lemon extends FruitV {
public boolean equals(Object 0 ) {
return (0 instanceof Lemon); }
}
Flat
FruitV
extends
I;
Treev t;
Treev
{}
Tr eev
{
Flat(FruitV _1,Treev
I
t
=
-I;
=
{}
-t) {
-t·}
,
}
class
Split
Treev I;
extends
Treev
{
Treev ';
Split(TreeV _1,Treev _') {
I
=
' =
_I;
_';
}
}
class Fig extends FruitV {
public boolean equals(Object 0) {
return (0 instanceof Fig) ; }
}
Let's say all Treevs are either iat, split, or
bud. Formulate a rigorous description for
Treevs.
Did you notice that we have redeined the
method equals in the variants of Fruitv?
Do Treev,s variants contain equals?
100
That probably means that we will need to
compare ruits and other things.
No, which means we won't compare them,
but we could.
Copyrighted Material
Chapter 7
How does the datatype TreeD difer rom all
the other datatypes we have seen before?
Let's add a visitor interface whose methods
produce booleans.
10
11
bTreeVisitoI {
lo'BudO;
boolean lo'Flat(FruitD I,TreeD t);
boolean lo'Split(TreeD l,TreeD ');
The name of the new datatype occurs twice
in its Split variant.
That just means extending what we have
with one method each.
class
interface
Bud
boolean
boolean
return
TreeD {
accept(bTreeVisitoI ask) {
ask.fo'BudO; }
extends
}
}
Flat extends TreeD {
FruitD I;
TreeD t;
Flat(FruitD _1,TreeD _t) {
I
-I;
t
_t; }
class
Here is the new datatype deinition.
abstract class
TreeD {
abstract
boolean
=
accept(bTreeVisitoI ask);
=
}
boolean
Revise the variants.
return
accept(bTreeVisitorI ask) {
ask.fo'Flat(f , t); }
}
Split extends TreeD {
TreeD I;
TreeD ';
Split(TreeD _l,TreeD _') {
I' _I;
_'; }
clss
=
=
boolean
return
accept(bTreeVisitorI ask) {
ask.fo'Split(I,'); }
}
But isn't bTreeVisitoI a pretty unusual
name?
Yes, it is. Hang in there, we need unusual
names for unusual interfaces. Here b reminds
us that the visitor's methods produce
12
Okay.
booleans.
OhMy!
Copyrighted Material
101
How many methods does the deinition of
blsFlatV
13
contain, assuming it implements
bTreeVisitoz?
produce?
What visitor does
Here is
a
TreeDs
hs three
variants.
What type of values do the methods of
blsFlatV
Three, because it works with TreeDs, nd the
datatype deinition for
blsFlatv
skeleton for
remind us of?
14
15
16
blsFlatV
class blsFlatv implements b TreeV i sitoz {
public
boolean jorBudO {
return
; }
public
boolean lorFlat(FruitD I.TreeD t) {
return
i}
public
boolean jorSplit(TreeD l,TreeD r) {
return
; }
}
booleans.
OnlyOnionsv
That's esy now.
clss blsFlatV implements bTreeVisitoz {
public
boolean jorBudO {
return true; }
public
boolean lorFlat(FruitD I.TreeD t) {
return t.accept(this); }
public
boolean jorSplit(TreeD l,TreeD r) {
return false; }
}
Fill in the blanks.
Deine the blsSplitV visitor, whose methods
check whether a
Split nd
102
Bud
TreeD
only.
is constructed with
17
Here is the esy part.
class b lsSp li t V implements bTreeVisitoz {
public
boolean jorBudO {
return true; }
public
boolean lorFlat(FruitD I,TreeD t) {
return false; }
public
boolean jorSplit(TreeD l,TreeD r) {
-- }
}
Cophted Maeial
Chapter 7
What is diicult about the lst line?
18
Isn't that esy?
19
20
And then?
21
If
l.accept(this)
is true, do we need to know whether
r. accept(this)
is true?
If
We need to check whether both
split trees.
1
and rare
Yes, we just use the methods of blsSplitV on I
and r.
Then we need to know that both are true.
Yes, because if both are true, we have a split
tree.
22
No, then the answer is false.
2
Now we can do it.
I. accept(this)
is false, do we need to know whether
r. accept (this)
is true?
Finish the deinition of blsSplitV using
if ( . )
return ...
else
return ...
.
.
3
class blsSplitV
implements
bTreeVisitoI {
public
boolean
return
public
boolean
return
public
forBudO {
true; }
forFlat(FruitD f.TreeD t) {
false; }
forSplit(TreeD I.TreeD r) {
ifl (l.accept(this))
return r.accept(this);
boolean
else
return
}
false; }
We could have ritten the if . .. s
retn 1. accept (this) && r. accept (this).
OhMy!
Copyrighted Material
103
Give an example of a TreeD for which the
methods of bls S pl itV respond with true.
How about one with ive uses of Split?
Does this TreeD have any ruit?
Deine the bHasFruitV visitor.
24
There is a trivial one:
new BudO.
25
H ere
26
No.
27
is one:
new Split(
new Split(
new BudO,
new Split(
new BudO,
new Bud())),
new Split(
new BudO,
new Split(
new BudO,
new Bud()))).
Here it is.
class bHasFruitV
implements bTreeVisitor {
public
boolean Jo'BudO {
return false; }
public
boolean Jo'Flat(FruitD J,TreeD t) {
return true; }
public
boolean Jo'Split(TreeD I,TreeD ') {
if! (l.accept(this))
return true;
else
return '.accept(this); }
}
We could have written the if.
retn
104
Copyrighted Material
1. accept (this)
.
s
II r.accept(this).
Chapter 7
28
What is the height of
new Split(
new Split(
new BudO,
new Flat(new LemonO,
new BudO)),
new Flat(new FigO
new Split(
new BudO,
new B u d())))?
3.
,
29
What is the height of
new Split(
new BudO,
new Flat(new LemonO,
new Bud()))?
What is the height of
new Flat(new LemonO,
new B u d())?
What is the height of
new BudO?
Do the methods of iHeightV work on a TreeP?
Is that what the i in ront of Height is all
about?
OhMy!
30
1.
31
o.
32
So what is the height of a TreeP?
2.
33
34
Just s in nature, the height of a tree is the
distance rom the beginning to the highest
bud in the tree.
Yes, nd they produce n into
It looks like i stands for int, doesn't it?
Copighted Mateial
105
35
What is the value of
new Split(
new Split(
4.
new BudO,
new Bud()),
new Flat(new Fi gO
new Flat(new LemonO,
new Flat(new AppleO,
new Bud()))))
.accept(new iHeightV())?
,
36
Why is the height 4?
Because the value of
new Split(
new BudO,
new Bud())
.accept(new iHeightV())
is 1; the value of
new Flat(new F i gO
new Flat(new LemonO,
new Flat(new AppleO,
new Bud())))
.accept(new iHeightV())
,
is 3; and the larger of the two numbers is 3.
37
And how do we get rom 3 to 4?
u
picks the larger of two numbers,
x
and
y.
1 38
1 When you enter this in a ile, use
Math. mx (x, y) .
Math is a clss that
i He i ghtV , s
Oh, that's nice. What kind of methods does
iHeight v deine?
contains mx s a (static) method.
methods mesure the heights of
the Treevs to which they correspond.
106
We need to add one to the larger of the
numbers so that we don't forget that the
original Treev ws constructed with Split and
those two Treevs.
39
Now that's a problem.
Copyrighted Material
Chapter 7
Why?
40
So what?
'
4
We deined only interfaces that produce
booleans in this chapter.
The methods of iHeightV produce ints, which
are not booleans.
Oay, so let's deine a visitor interface that
produces ints.
42
Yes, and once we have that we can add
another accept method to TreeD
43 Does that mean we can have two methods
with the same name in one clss?l
interface iTreeVisitoI {
int jorBudO;
int jorFlat(FruitD j, TreeD t);
int jorSplit(TreeD l,TreeD r);
}
abstract class TreeD {
abstract
boolean accept(bTreeVisitorI ask);
abstract
int accept(iTreeVisitoI ask);
}
We can have two methods with the same
name in the same clss s long s the types
of the things they consume are distinct.
Add the new accept methods to TreeD's
variants.
OhMy!
Start with the esy one.
It's almost the same s bTreeVisjto�
1 In Java, deining mUltiple methods with the same name
and diferent input types is called lIoverloading."
44
4
5
bTreeVisitorI is indeed diferent from
iTreeVisitorI, so we can have two versions of
accept in TreeD.
It is esy.
class Bud extends TreeD {
boolean accept(bTreeVisitorI ask) {
return ask.forBudO; }
int accept(iTreeVisitorI ask) {
return ask.forBudO; }
}
Copyrighted Material
107
The others are esy, too. We duplicate
accept.
46
class Flat extends TreeD {
FruitD I;
TreeD t;
Flat(FruitD -I ,TreeD _i) {
f
-/j
t _tj }
class Split extends TreeD {
TreeD l;
TreeD r;
Split(TreeD _l,TreeD _r) {
1= _Ij
r = _rj }
=
=
boolean accept(bTreeVisitoI ask) {
return ask.lorSplit(l,r)j }
int accept(iTreeVisitoI ask) {
return ask.forSplit(l,r)j }
boolean accept(b TreeVisitoI ask) {
return ask.lorFlat(f ,i); }
int accept(iTreeVisitoI ask) {
return ask.lorFlai(f,t)j }
}
}
47
Here is iHeightV
Complete these methods.
is the value of
new Split(
new BudO,
new Bud())
.accept(new iHeightV())?
And why is it
108
I?
That's esy now.
clss iHeightV implements iTreeVisitoI {
public int lorBudO {
return 0; }
public int lorFlat(FruitD j,TreeD t) {
return t.accept(this) + 1; }
public int jorSplit(TreeD I,TreeD r) {
return
(l.accept(this) U r.accept(this))
+ 1; }
}
class iHeightV implements iTreeVisitoI {
. public int lorBudO {
return
; }
public int lorFlat(FruitD I,TreeD t) {
return
; }
public int lorSplit(TreeD I,TreeD r) {
return
; }
}
I
What
We must also change the type of what the
new accept method consumes and produces.
4S
49
1, of
course.
Because
new Bud O. accept (new i Height v () )
is 0, the larger of 0 nd 0 is 0, and one more
is 1.
Copighted Mateial
Chapter 7
50
What is the value of
new Split(
new Split(
new Flat(new Fig(),
new Bud()),
new Flat(new Fig(),
new Bud())),
new Flat(new Fig(),
new Flat(new Lemon(),
new Flat(new Apple(),
new Bud()))))
. accept (
new tSubstV (
new Apple(),
new Fig()))?
Correct. Deine the tSubstV visitor.
51
52
What's the problem?
If the visitor tSubstV substitutes apples for
igs, here is what we get:
new Split(
new Split(
new Flat(new Apple(),
new Bud()),
new Flat(new Apple(),
new Bud())),
new Flat(new Apple(),
new Flat(new Lemon(),
new Flat(new Apple(),
new Bud())))).
It's like SubstFishV and SubstlntV from the
end of chapter 5, but we can't do it just yet.
Its methods produce TreeDs, neither ints nor
booleans, which means that we need to add
yet another interface.
interface tTreeVisitorI {
TreeD JorBudO;
TreeD JorFiat(FruitD J,TreeD t);
TreeD JorSpiit(TreeD i,TreeD r);
}
Good job. How about the datatype TreeD
53
Esy. Here is the abstract one.
abstract class TreeD {
abstract
boolean accept(bTreeVisitorI ask);
abstract
int accept(iTreeVisitorI ask);
abstract
TreeD accept(tTreeVisitorI ask);
}
OhMy!
Copyrighted Material
109
Deine the variants of TreeD.
54
No problem.
Bud
TreeD {
accept (bTreeVisitox ask) {
return ask.forBudOj }
int accept(iTreeVisitox ask) {
return ask.forBudOj }
TreeD accept(tTreeVisitox ask) {
return ask.forBudOj }
class
extends
boolean
}
Flat extends TreeD {
FruitD f;
TreeD t;
Flat(FruitD _f,TreeD _t) {
f -fj
t = _tj }
clss
=
accept(bTreeVisitox ask) {
ask.forFlat(J,t)j }
int accept(iTreeVisitox ask) {
return ask.forFlat(J,t)j }
TreeD accept(tTreeVisitox ask) {
return ask.forFlat(J,t)j }
boolean
return
}
Split extends TreeD {
TreeD I;
TreeD r;
Split(TreeD _I,TreeD _r) {
1= _lj
r = _rj }
class
accept (bTreeVisitox ask) {
ask.forSplit(l,r)j }
int accept(iTreeVisitox ask) {
return ask.forSplit(l,r)j }
TreeD accept(tTreeVisitox ask) {
return ask.forSplit(l,r)j }
boolean
return
}
110
Copyrighted Material
Chapter 7
55
Then deine tSubst v
That's esy, too. It has two ields, one for
the new FruitD and one for the old one, and
the rest is straightforward.
clss tSubst v implements tTreeVisitox {
FruitD n;
FruitV 0;
tSubstV(FruitD _n,FruitD _0) {
n
_n;
0 = _0; }
=
}
Here is a TreeD that hs tr ee Figs:
new Split(
new Split(
new Flat(new FigO,
new Bud()),
new Flat(new FigO,
new Bud())),
new Flat(new FigO,
new Flat(new LemonO,
new Flat(new AppleO,
new Bud())))).
56
Even the visitors are no longer
interesting.
class iOccursv implements iTreeVisitox {
FruitD a;
iOccursV(FruitD _a) {
a = _a; }
Now deine iOccursv, whose methods co unt
how oten some FruitD occurs in a tree.
}
OhMy!
public TreeD jorBudO {
return new BudO; }
public TreeD jorFlat(FruitD j,TreeD t) {
if ( 0. equals(t))
return new Flat(n,t.accept(this));
else
return new Flat(t,t.accept(this)); }
public TreeD jorSplit(TreeD I,TreeD r ) {
return new Split(l.accept(this),
r. accept(this)); }
public int jorBudO {
return 0; }
public int jorFlat(FruitD j,TreeD t) {
if (t. equals(a ))
return t.accept(this) + 1;
else
return t.accept(this); }
public int jorSplit(TreeD I,TreeD r ) {
return
l.accept(this) + r.accept(this); }
Copyrighted Material
111
Do you like your ruit with yogurt?
Is it disturbing that we have three nearly
identical versions of accept in TreeDs and its
variants?
57
58
59
Can we avoid it?
Remember Integer and Boolean? They make
it possible.
Here is the interface for a protocol that
produces Object in place of boolean, int,
and TreeD.
60
61
We prefer coconut sorbet.
Copying deinitions is always bad. If we
make a mistake nd copy a deinition, we
copy mistakes. If we modiy one, it's likely
that we might forget to modiy the other.
If boolean and int were clsses, we could
use Object for boolean, int, nd TreeD.
Unfortunately, they are not.
Yes, Boolean is the clss that corresponds to
boolean, nd Integer corresponds to into
Here they are.
Flat extends TreeD {
FruitD f;
TreeD t;
Flat(FruitD _f,TreeD _t) {
f = -fj
t _tj }
class
TreeVisito� {
Object forBudOj
Object forFlat(FruitD f,TreeD t);
Object forSplit(TreeD l,TreeD r);
interface
}
Here is the datatype and the Bud variant.
abstract class
=
}
TreeD {
abstract
Object accept(TreeVisito� ask);
Split extends TreeD {
TreeD l;
TreeD r;
Split(TreeD _l,TreeD _r) {
l = _lj
r _rj }
class
}
Bud extends TreeD {
Object accept(TreeVisito� ask) {
return ask.forBudOj }
class
}
Deine the remaining variants of TreeD.
112
Object accept(TreeVisito� ask) {
return ask.forFlat(f,t)j }
=
}
Object accept(TreeVisito� ask) {
return ask.forSplit(l, r)j }
Copyrighted Material
Chapter 7
Good. Now deine IsFlatV, an Object
producing version of blsFlatv.
62
class IsFlatV implements TreeVisitorr {
public Object forBudO {
return new Boolean(true); }
public Object forFlat(FruitV f ,Treev t) {
return t.accept(this); }
public Object forSplit(TreeV l,Treev r ) {
return new Boolean(false); }
}
And how about IsSplitv?
63
Okay, here it is.
64
class IsSplitV implements TreeVisitorr {
public Object forBudO {
return new Boolean(true); }
public Object forFlat(FruitV f,Treev t) {
return new Boolean(false); }
public Object for Split(TreeV l,Treev r ) {
if (( (Boolean) (l. accept(this)))
. boolean Value())
return r. accept(this);
else
return new Boolean(false); }
}
Will the conversion always work?
That's no big deal.
Now that's diferent. Here we need a way to
determine the underlying boolean of the
Boolean that is produced by l.accept(this) in
the original deinition.
Oh, because l.accept(this) produces an
Object, we must irst convert 1 it to a Boolean.
Then we can determine the underlying
boolean with the boolean Value method. We
have seen this in chapter 5 when we
converted an Object to a OneMoreThan.
1 If Jaa had parametric polymorphism for methods, no
downward cst would be necessary for our visitors (Martin
Odersky and Philip Wadler, Pizza into Java: ranslating
Theory into Practice, Confeence Rod on Pinciples of
Pogammmg Languages, 14-159. Paris, 1997).
65
Yes, because the Object produced by
l. accept ( this) is always a Boolean.
The Seventh Bit of Advice
hen designing visitor protocols for
many diferent types, create a unifying
potocol using Object.
OhMy!
Copyrighted Material
113
Did you think that ws bad? Then study
this deinition during your next break.
66
Oh my.,
class Occursv implements TreeVisitoI {
FruitD a;
OccursV (FruitD _a) {
a = _a; }
public Object jorBudO {
return new Integer(O); }
public Object jorFlat(FruitD j,TreeD t) {
if (I. equals ( a))
return
new Integer(((lnteger)
(t. accept(this)))
.intValueO
+ 1);
else
return t.accept(this); }
public Object jor Split(TreeD l,TreeD r) {
return
new Integer(((lnteger)
(l. accept(this)))
.intValueO
+
}
114
((Integer)
(r.accept(this)))
.intValue())j }
Copyrighted Material
Chapter 7
Copyrighted Material
1
What is the value of
12.
(7 + ((4- 3) x5))?
12,
What is the value of
(+ 7 (x (- 4 3 ) 5))?
because we have just rewritten the
previous expression with preix operators.
new Integer(12),
What is the value of
new Plus(
new Const(new Integer(7)),
new Prod(
new Dif(
new Const(new Integer(4)),
new Const(new Integer(3 ))),
new Const(new Integer(5))))?
because we have just rewritten the
previous expression using I nteger and
constructors.
A datatype and its variants that represent
Where do the constructors come from?
arithmetic expressions.
Did you like that?
What is the value of
5
6
So far, so good.
{7,5}.
({7,5} U (({4} \ {3}) n {5}))?
What is the value of
(u {7,5} (n (\ {4} {3}) {5} ))?
What is the value of
(+ {7,5} ( x (- {4} {3}) {5}))?
Like Father, Like
Son
{7,5},
we just went from inix to preix notation.
{7,5},
we just renamed the operators.
Copyrighted Material
117
new EmptyO
.add(new Integer(7))
.add(new Integer(5)),
What is the value of
new P lu s(
new Const(new EmptyO
.add(new Integer(7))
.add(new Integer(5))),
new Pr od(
new Dif(
new Const(new EmptyO
.add(new Integer(4))),
new Const(new EmptyO
.add(new Integer(3)))),
new Const(new EmptyO
. add (new Integer(5)))))?
Where do the constructors come rom?
because we have just rewritten the
previous expression using the constructors.
10
A datatype and its variants that represent
set expressions.
11
Do you still like it?
Does the arithmetic expression look like the
12
set expression?
Sure, why not.
Yes, they look the same except for the
constants:
new Plus(
new Const(e),
new Prod(
new Diff(
new Const(e),
new Const(e)),
new Const(e))).
Let's say that an expression is either
a
a
a
Plus(exprl,expr2),
Diff(exprl, expr2)'
Prod(exprl,expr2),
or
a constant,
where
exprl
and
expr2 stand
for arbitrary
expressions. What should be the visitor
interface?
13
That's a tricky question.
interface Exp rVi si t ox {
Object jorPlus(ExprD l,ExprD r);
Object jorDiJ(ExprD l,ExprD r);
Object jorPod(ExprD l,ExprD r);
Object jorConst(Object c);
}
118
Copyrighted Material
Chapter 8
Good answer. Here is the datatype now.
class Plus
ExprD l;
abstract class ExprD {
abstract
}
14
extends
ExprD {
ExprD r;
Plus(ExprD _1,ExprD _r ) {
I
_Ii
r
_r; }
Object accept(ExprVisitox ask);
=
=
Deine the ariants of the datatype and equip
them with an
Objects.
accept
met hod
that produces
}
Object accept(ExprVisitox ask) {
return ask.forPlus(I,r); }
clss Diff extends ExprD {
ExprD I;
ExprD r;
Diff(ExprD _1,ExprD _r) {
I
=
r =
}
_Ii
-ri
}
Object accept(ExprVisitox ask) {
return ask.forDif(I,r)j }
class Prod extends ExprD {
ExprD I;
ExprD r;
Prod(ExprD _1,ExprD _r) {
I
_Ij
r = -r', }
}
=
Object accept(ExprVisitox ask) {
return ask.forPod(I,r); }
class Const extends ExprD {
Object C;
Const(Object _c) {
c = _Cj }
}
Like Father, Like
Son
Object accept(ExprVisitox ask) {
return ask.forConst( c ) j }
Copyrighted Material
119
Can we now deine a visitor whose methods
15
Yes, we can. It must have four methods, one
determine the value of an arithmetic
per variant, and it is like
expression?
previous chapter.
16
How do we add
intValue to determine the ints that
Integers, and then add
correspond to the
and
them together.
new Integer(2)?
17
But what is the result of
new Integer(3).intValueO
+
new Integer(2).intValueO?
How do we turn that into an
Integer?
Okay, so here is a skeleton of
IntEvalv
class IntEvalv implements ExprVisitox {
public Object forPlus(ExprV l,Exprv r) {
return plus(l.accept(this),
r. accept (this)); }
public Object forDif(ExprV l,Exprv r) {
return dif(l.accept(this),
r.accept(this)); }
public Object forPod(ExprV l,Exprv r ) {
return pod(l.accept(this),
r.accept(this)); }
public Object forConst(Object c) {
return c; }
Object plUS(_l l,-2 r ) {
return -3;}
Object dif(-l l'-2 r) {
return -4; }
Object Pod(_l l,-2 r ) {
return -5;}
}
120
rom the
We have done this before. We use the
method
new Integer(3)
Occursv
18
19
An
int,
We use
what else?
new Integer(... ) .
That's an interesting skeleton. It contains
ive diferent kinds of blanks and two of them
occur three times each. But we can see the
bones only. Where is the beef?
Copyrighted Material
Chapter 8
How does
!oTPlus
20
work?
It consumes two
ExprDs, determines their
pl us es them.
respective values, and
21
How are the values represented?
As Objects,
because we are using our most
general kind of
So what kind of values must
plus
consume?
22
(and
most recent) visitor.
Objects,
because that's what
l.accept(this)
and
T.accept(this)
produce.
What must we put in the irst and second
23
Object.
blanks?
Can we add
24
Objects?
No, we must convert them to
Integers
irst
and extract their underlying ints.
Can we convert all
Objects
to Integers?
25
No, but all
made with
Objects produced by IntEvalV are
new Integer(.. . ) so that this
,
conversion always succeeds.
Is
26
that true? What is the value of
Wow. At some level, this is nonsense.
new Plus(
new Const(n ew Empty()),
new Const(new Integer(5)))
.accept(new IntEvalV ()) ?
Correct, so sometimes the conversion may
fail, because we use an instance of
27
What should we do?
IntEvalV
on nonsensical arithmetic expressions.
Like Father, Like
Son
Copyrighted Material
121
28
We agree to avoid such arithmetic
expressions. 1
1 In other words, we have
usafe
And their set expressions, too.
evaluators for our
expressions. One way to make them safe is to add a method
that hs whether constnts are istancs of the proper
lss and that raiss an exception [ l:chapter 7). An
alternative is to deine a visitor that type checks the
rithmetic exprssions we wish to evaluate.
If we want to add
l
and
r, we write
new Integer(
((Integer)l).int Value 0
+
((Integer)r). int Value 0 ).
Complete the deinition now.
29
Now it's esy. Here we go.
clss IntEvalV implements ExprVisitor {
public Object forPlus(ExprV l,Exprv r) {
return plus(l. accept(this),
r.accept(this)); }
public Object forDif(ExprV l,Exprv r) {
return dif (l. accept(this) "
r.accept(this)); }
public Object forPod(ExprV l,Exprv r) {
return pod(l.accept(this),
r. accept (this)) ; }
public Object forConst(Object c ) {
return c; }
Object plus(Object l,Object r) {
return
new Integer(
((Integer)l). intValue 0
+
(( Integer) r ) . intValue ()); }
Object dif(Object l,Object r ) {
return
new Integer(
((Integer)l).intValue 0
((lnteger)r).intValue()); }
Object pod(Object l,Object r ) {
return
new Integer(
((Integer)l).int Value 0
*
((lnteger)r).intValue()); }
}
122
Copyrighted Material
Chapter 8
That one ws pretty esy, wsn't it?
•
What do we need to Implement one for sets?
That's correct, and here is everthing.
30
31
Yes. Let's implement an
ExprVisitorX for sets.
We certainly need methods for
d if ing, and poding sets.
32
Whoa.
33
We use our words:
plusing,
abstract class SetD {
SetD add(lnteger i) {
}
if (mem(i»
return this;
else
return new Add(i,this); }
abstract boolean mem(lnteger i);
abstract SetD plus(SetD s);
abstract SetD dif ( SetD s);
abstract SetD pod(SetD s);
Explain the method in the nested box in
"As its name says,
your own words.
add adds an element to
a set. If the element is a member of the
set, the set remains the same; otherwise, a
new
Why is this so tricky?
3.
set is constructed with
Add."
Constructors always construct, and
add does
not always construct.
Do we need to understand that?
3'
Not now, but feel free to absorb it when you
have the time.
Like Father, Like
Son
Copighted Mateial
123
Deine the variants
Empty
and
Add
for
SetD
36
Here we go.
-�
-
class Empy extends SetD {
boolean mem(lnteger i) {
return false; }
SetD plus ( SetD s) {
return s; }
SetD dif(SetD s) {
return new EmpyOj }
SetD prod(SetD s) {
return new EmpyOj }
}
class Add extends SetD {
Integer i;
SetD s;
Add(lnteger _i,SetD _s) {
i = _i;
S
_Sj }
=
}
124
boolean mem(lnteger n) {
if (i . equals( n ) )
return true;
else
return s.mem(n)j }
SetD plus(SetD t) {
return s.plus(t.add(i)); }
SetD dif(SetD t) {
if (t.mem(i))
return s.dif(t)j
else
return s.dif( t}.add(i)j }
SetD pod(SetD t} {
if (t.mem(i))
return s.prod(t).add(i);
else
return s.pod(t}; }
Copighed Mateial
Chapter 8
Do we need to understand these deinitions?
37
Not now, but feel ree to think about them
when you have the time. We haven't even
used visitors to deine operations for union,
set-diference, and intersection, but we trust
you can.
What do we have to change in IntEvalV to
V
obtin Set E v al , an evaluator for set
38
Not much, just
plus, diJ,
and
pod.
expressions?
39
How should we do that?
Oh, that's a piece of pie. We just copy the
IntEvalV and replace
prod methods.
deinition of
diJ,
That's the worst way of doing that.
hy should we throw away more than half
40
41
and
its
plus,
What?
That's true. If we copied the deinition and
changed it, we would have identical copies of
of what we have?
JorPlus, JorDiJ, JorPod,
and
should reuse this deinition. 1
JorConst.
We
1 Sometims we do not have license to see the deinitions1 so
copying might not even be an option.
Yes, and we are about to show you better
ways. How do we have to change
and
pod?
plus, diJ,
42
That part is esy:
Object plus(Object I Obj ect r) {
return ((SetD)l).plus((SetD)r); }
nd
Obj ect diJ(Object l Obj ect r) {
return ((SetD)I). diJ((SetD)r); }
,
,
and
Object pod(Object l,Object r) {
return ((SetD)I).pod((SetD)r); }.
Like Father, Like
Son
Copyrighted Material
125
Very good, and
if we
deine SetEvalV
extension of IntEvalV, that ' s
all
s
an
43
Now
that's much
esier than copying and
modi y in g .
we have to
put inside of SetEvalV
class SetEvalV extends IntEvalV {
Object plus(Object l Obj ect r) {
return ((SetV)l).plus((SetD)r); }
Object dif(Object I,Object r) {
return ((SetV)I).dif{{SetV)r); }
Object pod(Object I,Object r) {
return ((SetV)l).prod{{SetV)r); }
}
,
Is it
like
44
equals?
Yes, when we include
equals
in
our clss
Object.
plus, dif, and
deinitions, we override the one in
Here, we override the methods
pod
How many methods
rom
IntEvalV are
45
s
we extend IntEvalV
Three.
overridden in SetEvalv?
How many methods rom IntEvalv are not
46
overridden in SetEvalv?
Does SetEvalV implement ExprVisito,x?
48
Does SetEvalv extend IntEvalv?
Does IntEvalv implement ExprVisito,x?
Does SetEvalv implement ExprVisitox?
126
47
49
50
Four: forPlus, forDif, forPod,
forConst.
nd
It doesn't say so.
It says so.
It says so.
By
implication.
Copighted Mateial
Chapter 8
51
That's correct. What is the value of
new Prod(
new Const(new EmptyO
.add(new Integer(7»),
new Const(new EmpyO
.add(new I ntege r(3» »
.accept(new SetEvaIV())?
now?
52
What type of value is
Interesting question. How does this work
It is a
new Prod(
new Const(new Empty()
Prod
and therefore an
E xprD
. add (new I ntege r ( 7 » ) ,
new Const(new Empty()
. add (new Int ege r (3 »» ) ?
And what does
3
5
accept consume?
An instance of
SetEvalV,
but its type is
ExprVisito�
54
What is
new SetEvaIV().forPod(
new Const(new Empy()
of next, because
.add(new Integer(7»),
method
is
with
ask,
l, and
r
replaced by what they
stand for .
. add(new Integer(3»))?
SetEvalV's
it
ask.forPod{ l,r),
new Const(new Empty()
Where is the deinition of
That's what we need to determine the value
5
5
It is in
IntEvalV
forProd?
56
Suppose we had the values of
new Const(new EmptyO
. add(new I nteger(7»)
. accept (this)
If their values were
A
and
B,
we would have
to determine the value of
prod{A,B) .
and
new Const(new EmptyO
.add(new Integer(3»)
. accept (this).
What would we have to evalu ate next?
Like Father, Like Son
Copyrighted Material
127
Isn't that strange?
57
Why?
So far, we have always used a method on a
58
That ' s true. What is the object with which
we u se
particular object.
It is
59
this object.
pod(A,B)?
Oh, does that mean we should evaluate
new SetEvaIVO.pod(A,B)?
Absolutely. If the use of
a
method omits the
60
That clariies things.
object, we take the one that we were working
with before.
61
Good. And now what?
Now we still need to determine the values of
new Const(new EmpyO
.add(new Integer(7)))
. accept (this)
and
new Const(new Empy()
.add(new Integer(3)))
.accept(this).
62
The values are obviously
It, too, is in
IntEvalv.
new EmptyO
add (new Integer(7))
.
and
new EmpyO
.add(new Integer(3)).
Where is the deinition of forConst that
determines these values?
Here is the next expression in our sequence:
new SetEvalvO
.prod(new EmptyO
. add(new Integer(7)),
new EmptyO
.add(new Integer(3))).
Where does
128
pod
63
The object is an instance
of SetEvalv,
IntEvalv
overrides the pod method in
which
with
its own .
come from?
Copyrighted Material
Chapter 8
64
What next?
65
Is
new EmpyO.add(new Integer(7))
an instance of Setv?
And how about
new EmptyO.add(new Integer(3))?
66
And that is why the method must contain a 6
conversion rom Object to SetVs.
Time for the lst question. Where does this
pod come from now?
70
We overrode that, too.
Is it natural that SetEvalV extends IntEvalV?
Son
68
Of course it is, but the type of l.accept(this),
which is where it comes from, is Object.
It's the same.
This example makes the need for conversions
obvious again.
This one belongs to SetV or more precisely
its Empy and Add variants.
69 It determines the intersection of one SetV
with another S etV, but didn't we agree that
the previous question ws the lst question
on that topic?
And what does pod do?
Like Father, Like
7
Next we need to determine the value of
((SetV)(new EmptyO
. add(new Integer(7))))
. pod((SetV)new EmptyO
.add(new Integer(3))),
because it is
(( Se tV) ( I. accept( this)))
. prod ((S etV) r. accept ( this))
with l. accept(this) and r.accept(this)
replaced by their respective values.
71
Thanks, guys.
No, not at all.
Copyrighted Material
129
Why
did
72
we do that?
Because we deined IntEvalV
1
irst.l
Sometimes we may need to extend clsses that are used in
severl diferent programs. Unless we wish to maintain
multiple copies of the me clss, e should extend it.-Jaa
is obje-oriented,
so it may o be the ce that e quire
the object code of a clss and its interface, but not its source
text. If e wish to enrich the unctionality of this kind of
clss, we must lso extend it.
But j ust because something works,
mean it's rational.
it
doesn't
What distinguishes IntEvalV rom SetEvalV?
What are the pieces that they have in
common?
Good. Here is how
we express that.
73
7'
7S
78
Yes, let's do better. We have deined all
these clsses ourselves, so we are free to
rearrange them any way we want.
The methods plus, dif, and pod.
They share the methods forPlus, forDif,
jorProd, and jorConst.
Isn't this
abstract
clss like Pointv?
abstract clss Evalv
implements ExprVisitox {
public Object jorPlus(ExprV I,Exprv r ) {
return plus(l.accept(this),
r.accept(this)); }
public Object jorDif(ExprV l,Exprv r) {
return dif(l. accept (this),
r.accept(this)); }
public Object jorPod(ExprV I,Exprv r) {
return pod (I. accept(this),
r.accept(this)); }
public Object jorConst(Object c) {
return C; }
abstract
Object plus(Object l,Object r);
abstract
Object dif(Object I,Object r};
abstract
Object prod(Object I,Object r);
}
130
Copighted Mateial
Chapter 8
Yes, we can think of it as a datatype for
EvarD visitors that collects all the common
elements s concrete methods. The pieces
that difer from one variant to another are
speciied s abstract methods.
We
77
78
deine IntEvalV extending Eva I> .
class IntEvalV extends EvalV {
Object plus(Object I,Object r) {
return
new Integer(
((Integer) l). intValue 0
What do we do now?
is bsically like the original but extends
Eval>, not IntEvalv.
It
class SetEvalv extends EvalV {
Object plus(Object I,Object r) {
return « SetD)l).plus«SetD)r); }
Object dif(Object I,Object r) {
return «SetD)l).dif« SetD)r); }
Object prod(Object l,Object r) {
return « SetD)l).prod( SetD)r); }
}
+
«Integer)r). intValue()); }
Object dif(Object I,Object r ) {
return
new Integer(
«Integer)l). intValue 0
«lnteger)r).intValue())j}
Object prod(Object I,Object r) {
return
new Integer(
((Integer) l). int Value 0
*
«lnteger)r). intValue()); }
}
Deine SetEvalv.
Is it natural for two evaluators
same footing?
Time for supper.
Like Father, Like Son
to be
on the
79
80
Much more so than one extending the other.
If you are neither hungry nor tired, you may
continue.
Copyrighted Material
131
Remember
SubstV
from
chapter 6?
81
class SubstV implements PieVisitoI {
Object n;
Object 0;
Substv (Object _n,Object _0 ) {
n
o
=
=
_n;
_0;
Yes,
and
LtdSubstV, too.
class LtdSubstV implements PieVisitoI {
int c;
Object n;
Object 0;
LtdSubstV(int _c , Obj ect _n,Object _ 0) {
c
_c;
n _n;
0= _0; }
}
=
=
public PieD forBotO {
return new Bot(); }
public PieD forTop(Object t , Pi eD r) {
if (0. equals(t))
return
new Top(n,r.accept(this));
else
return
new Top(t,r.accept(this) ); }
public PieD forBotO {
return new Bot(); }
public PieD forTop(Object t, Pi eD r) {
if(c
0)
return new Top(t,r);
else
if (0. equals (t))
return
new Top ( n,
r.accept(
new LtdSubstV(c -l,n,o)));
else
return
new Top(t,r.accept(this)); }
==
}
}
What do
Where
the
do
two
visitors
What else does the
82
83
they difer?
And where do we put the
clsses have in common?
132
have in common?
pieces
that two
abstract clss
contain?
84
85
Many things:
n,
0,
and forBot.
They difer in forTop ,
an extra ield.
We
but
LtdSubstV also hs
put them into an abstract
clss.
It speciies the pieces that are diferent
they are needed for all extensions.
Copyrighted Material
if
Chapter 8
Deine the
abstract class Subst>,
which
86
contains ll the common pieces and speciies
abstract class Subst>
implements PieVisitox {
Object n;
Object 0;
public Pie> jorBot O {
return new Bot(); }
public
abstract Pie> jorTop(Object t,Pie> r);
}
what a concrete pie substituter must contain
in addition.
We can deine
SubstV
by extending
Subst>
87
LtdSubstv.
}
Do the two remaining clsses still have things
in
common?
Substv.
=
public Pie> jorTop(Object t,Pie> r) {
if (o.equals{t))
return
new Top{n, r. accept{thi s));
else
return
new Top{t, r.accept(this)); }
Deine
It also extends
clss LtdSubstV extends Subst> {
int c;
LtdSubstV(int _c,Object _n,Object _0) {
n = _n;
0=_0;
c _c ; }
class SubstV extends Subst> {
SubstV(Object _n,Object _0) {
n= _n;
0= _0; }
}
It's not a big deal, except for the ields.
88
public Pie> jorTop(O bj ect t,Pie> r) {
if (c == 0)
return new To p{t, r);
else
if (o.equals{t))
return
new Top(n,
r.accept(
new LtdSubstV(c - 1,n,0)));
else
return
new To p{t , r. ac ce pt{this) ) ; }
No, but the constructors have some overlap.
Shouldn't we lit the
Subst>, because
SubstV
constructor into
it holds the common
elements?
Like Father, Like Son
Copighted Mateial
133
That's a great idea. Here is the new version
of
89
SubstD
We must use
public Piev JorTop(Object t,Piev r) {
if ( 0. equals ( t))
return
new Top(n,r.accept(this))j
else
return
new Top(t,r.accept(this))j }
n = _nj
}
_O J }
public PieD jorBotO {
return new BotO; }
public
abstract PieD jorTop(Object t,PieD r};
Revise SubstV
and
in the constructors.
clss Substv extends SubstD {
SubstV (Object _n,Object _0 ) {
super(_n,_o)j}
abstract class SubstD
implements PieVisito� {
Object nj
Object OJ
SubstV(Object _n,Object _0) {
0=
super
}
clss LtdSubstV extends SubstD {
int Cj
LtdSubstv(int _c, Object _n,Object _0 ) {
super(_n,_o)j
c _c; }
LtdSubstV
=
public PieD jorTop(Object t,PieD r) {
if(c
0)
return new Top(t,r)j
else
if( 0. equals ( t))
return
new Top(n,
r.accept(
new LtdSubstV(c -l,n,o)));
else
return
new Top(t,r.accept(this)); }
==
}
Ws that irst part esy?
134
90
i pie.
Copighted Mateial
Chapter 8
That's neat. How about some art work?
91
Is this called a pie chart?
accept
No, but the picture captures the important
92
- PieVisitorT
Fine.
relationships.
Is it also possible to deine
extension
of Substv?
LtdSubst v
s an
It may even be better. In some sense,
LtdSubst v j ust
adds a service to
Subst v:
It
counts s it substitutes.
LtdSubstv is deined s an extension of
SubstV, what hs to be added and what hs
If
93
94
As we just said,
c
is an addition and
forTop
is diferent.
to be changed?
The Eighth Bit of Advice
hen extending a class, us e overriding
to enrich its functionality.
Like Father, Like
Son
Copyrighted Material
135
Here is the good old deinition of
from chapter
6
SubstV
95
The rest follows naturally, just s with the
ealuators and the previous version of these
one more time.
two clsses.
class SubstV implements PieVisitox {
Object n;
Object 0;
SubstV(Object _n,Object _0) {
n = _n;
0= _0; }
}
clss LtdSubstV extends SubstV {
int c;
LtdSubstV(i nt _c,Object _n,Object _0) {
super( _n,_o);
c= _c; }
public PieD forE ot O {
return new BotO ; }
public PieD forTop(Object t,PieD r) {
if (0. equals (t))
return
new Top(n, r.accept(this));
else
return
new Top(t, r.accept(this)); }
Deine
LtdSubstV
s an extension of
Substv.
}
96
Let's draw a picture.
public PieD forTop(Object t,PieD r) {
if (c==O)
return new Top(t,r);
else
if (0. equals (t))
return
new Top(n,
r.accept(
new LtdSubstV(c - 1, n,0)));
else
return
new Top(t,r.accept(this)); }
Fine, and don't forget to use lines, rather
than arrows, for
implements.
accept
You deserve a super-deluxe pizza now.
136
97
- PieVisitox
It's already on its way.
Copyrighted Material
Chapter 8
@o
u� � �@l �rr
Copyrighted Material
Remember
Pointv?
If not, here is the
datatype with one additional method,
We will talk about
minus.
minus when we need it,
PointV, s variants.
but for now, just recall
abstract class PointV {
int x;
int y;
PointV ( int _x,int _ y ) {
x -Xj
It hs been a long time since we discussed
the datatype
=
-Yj
}
}
V
boolean closerToO(Point p) {
return
distanceToO() S p.distance ToOO; }
PointV minus ( PointV p) {
return
new CatesianPt (x - p.x,y - p.y); }
abstract int distance ToOO;
}
ManhattanPt.
int distance ToOO {
return l VX2 + y2J; }
class ManhattanPt extends PointV {
ManhattanPt ( int _x,int _y) {
super(_x,_y); }
}
Good. Take a look at this extension of
int distanceToOO {
return x + y; }
t uses
.x
.y
class ShadowedManhattanPt
extends ManhattanPt {
int .x;
int .y;
ShadowedManhattanPt ( int _x,
int _y,
int _.x,
int _.y) {
super(_x,_y);
.x _.xj
.y _.yj }
and its variants, but
class CatesianPt extends PointV {
CatesianPt (int _x,int _y) {
super(_x,_y); }
=
Y
PointV
they are not that esy to forget.
=
=
_.x;
_.y;
in addition to
super( _x ,_ y ) .
=
=
}
int distanceToOO {
return
super.distanceToOO
+ .x
+
.yj }
What is unusual about the constructor?
Be
a
Good Visitor
Copyrighted Material
139
And what does that mean?
By using
super
on the irst two values
consumed, the constructor creates a
ShadowedManhattanPt
with proper
x
and y
ields. The rest guarantees that this newly
created point also contains values for the two
additional ields.
Okay. So what is a
ShadowedManhattanPt?
It is a ManhattanPt with two additional
ields: ..x and ..y. These two represent the
information that determines how far the
shadow is from the point with the ields
x
and y.
ShadowedManhattanPt:
new ShadowedManhattanPt(2,3,1,O)?
Is this a
What is unusual about
distance ToO?
5
Yes.
Unlike any other method we have seen
before, it contains the word
super.
So fr,
we have only seen it used in constructors.
What does it mean?
Here,
super. distance ToO
refers to the
method deinition o f distance ToO that is
Okay. That means we just add
we evaluate
x
and y when
super.distanceToO().
relevant in the clss that
ShadowedManhattanPt
extends.
Correct. But what would we have done if
Then we would refer to the deinition in the
ManhattanPt had
clss that
not deined
distance ToO?
Yes, and so on. What is the value of
new ShadowedManhattanPt(2,3,1,O)
distanceToO()?
ManhattanPt
It is 6, because
to add 1 and
O.
2
+
3 is
extends, right?
5, and then we have
.
140
Copyrighted Material
Chapter 9
Precisely. Now take a look at this extension
of
10
discussed this kind of
Shadowed Manhattan Pt.
Nothing. We just
constructor for
Cartesian Pt.
clss ShadowedCatesianPt
extends CatesianPt {
int l,;
int ly;
ShadowedCatesianPt(int -x,
int _y,
int �x,
int �y) {
super(-x,_y);
l,
�';
ly �y; }
=
=
int distanceToOO {
return
super.distanceToOO
+
L Jl� + l�J; }
}
What is unusual about the constructor?
Is this a
ShadowedCartesianPt:
new ShadowedCatesianPt(12,5,3,4)?
And what is the
value of
new ShadowedCatesianPt(12,5,3,4)
distanceToOO?
11
12
Yes.
It is 18, because the distance of the
Cartesian point (12,5) is
5,
.
. 1l2
V x
with
W hat do
Be
a
we expect?
Good Visitor
13
13,
and then we add
because that is the value of
+
l2y
lx replaced by 3
and
ly replaced
by
4.
17, obviously.
Copyighted Mateial
141
14
Why 17?
B ecause we need to think of th i s point s if it
were
new CatesianPt(15,9).
We need to add \
we t hi nk of a
x
to
x
and \y to
y
when
15
ShadowedCatesianPt.
And indeed , the value of
new CatesianPt(15,9)
distanceToOO
17.
.
is
Does this explain how
distanceToO
should
16
Completely. It should make a new
mesure the distance of a
CatesianPt
ShadowedCatesianPt to
ields and should then mesure the distanc'
the origin?
by adding the corresponding
of that new point to the origin.
Revise the deinit ion of
ShadowedCatesianPt
11
Oay.
accordingly.
class ShadowedCatesianPt
extends CatesianPt {
jnt \x;
jnt \y;
ShadowedCatesianPt(int _x,
jnt _y,
int _\x,
int _\y) {
super(_x,_y);
\x
\y
=
=
\x;
_\y; }
int distanceToOO {
return
new CatesianPt(x +
.distanceToOO; }
\x,y +
\y)
}
Do we still need the new
distanceToO
CatesianPt
ater
hs d et erm i ned the distance?
18
No, once we have the distance, we have
need for this
1
And neither does Java. Object-oriented languages manage
memory so that prorammers
of design
142
no
point. 1
nd
Copyrighted Material
implementation.
can
focus on the
diicult
parts
Chapter 9
19 true,
Correct. W hat is the value of
because the distance of t he CatesianPt to
new CatesianPt(3,4)
.closerToO(
new ShadowedCatesianPt(1,5,1,2))?
Is the rest of this chapter obvious, too?
a
ShadowedCatesianPt
20
How did we determine that value?
That ws a hint that now is
the origin is 5, while that of the
good time to
21
22
take a break.
Come back fully rested. You will more than
23
need it.
Are sandwiches square meals for you?
25
Here are circles and squares.
}
=
_r;
That's obvious.
W hat ?
Oh. Well, that makes the hint obvious.
Fine.
They can be well-rounded.
Then this must be the datatype that goes
with it.
class Circle extends ShapeD {
int r;
Circle(int _r) {
r
2'
is 7.
abstract class ShapeD {
abstract
boolean accept(ShapeVisitox ask);
}
boolean accept(ShapeVisitox ask) {
return ask.forCircle(r); }
}
class Square extends ShapeD {
int s;
Sq u a re ( int s ) {
s
=
_
s;
}
_
boolean accept(ShapeVisitorI ask) {
return ask.forSquare(s); }
}
Be
a
Good Visitor
Copyrighted Material
143
Very good. We also need an interface, and
here
it
26
It suggests that there is another variant:
Trans.
is.
interface ShapeVisitox {
boolean forCircle(int r);
boolean forSquare(int s);
boolean forrans(PointV q,Shapev s);
}
Yes and we will need this third variant.
27
but what's the poi nt?
clss Trans! extends Shapev {
PointV q;
ShapeV s;
Trans(PointV _q,ShapeV _s) {
q
s
}
=
-q;
=
_s; }
Okay, now this looks pretty straightforward,
boolean accept(ShapeVisitox ask) {
return ask.forrans(q,s); }
1 A better name is Trnslation.
28
Let's create a circle.
No problem:
new Circle(10).
How should we think about that circle?
29
We should think about it
radius
Good. So how should we think about
new
a circle wi t h
Well, that's a square whose sides are
10
units
long.
Square(lO)?
Where are our circle and square located?
144
30
s
10.
31
What does that mean?
Copyrighted Material
Chapter 9
Suppose we wish to determine whether some
CartesianPt
32
is inside of the circle?
In that
cse,
s
we must think of the circle
being drawn around the origin.
33
And how about the square?
There are many ways to think about the
location of the square.
34
Pick one.
Let's say the square's southwest corner sits
on the origin.
That will do. Is the
coordinate
10
CatesianPt
and y coordinate
with
10
x
35
.
Yes, It
.
IS.
but barely.
inside the
square?
36
And how about the circle?
Certainly not, because the circle's radius is
10,
but the distance of the point to the origin
is 14.
Are all circles and squares located at the
37
We have no choice so far, because
Square
origin?
Circle
and
only contain one ield each: the radius
and the length of a side, respectively.
This is where
new
Trans
comes in. What is
38
Trans(
new CatesianPt(5,6),
new Circle(10))?
new
CartesianPt(5,6)?
Is
new
CartesianPt(10,10)
Trans we can
10 at a point like
new CartesianPt(5,6).
place a circle of
radius
How do we place a square's southwest corner
at
Aha. With
inside either the
39
Also with
40
It is inside both of them.
Trans:
Trans(
new CatesianPt(5,6),
new Square(10)).
new
circle or the square that we just referred to?
Be
a
Good Visitor
Copyrighted Material
145
How do we determine whether some point is
41
inside a circle?
If the circle is located at the origin, it is
simple. We determine the distance of the
point to the origin and whether it is smaller
than the radius.
How do we determine whether some point is
42
inside a square?
If the square is located at the origin, it is
simple. We check whether the point's
coordinate is between 0 and
s,
x
the length of
the side of the square.
43
Is that all?
No, we also need to do that for the y
coordinate.
44
Aren't we on a roll?
We have only done the esy stuf so fr. It is
not clear how to check these things when the
circle or the square are not located at the
origin.
Let's take a look at our circle around
new
45
We can if we translate all other points by an
appropriate amount.
CatesianPt(5,6)
again. Can we think of this point
s
the
origin?
46
By how much?
By
5
in the
x
direction and
direction, respectively.
How could we translate the points by an
47
accomplishes that?
146
in the y
We could subtract the appropriate amount
from each point.
appropriate amount?
Is there a method in
6
PointP
that
48
Yes. Is that why we included minus in the
new deinition of PointP?
Copyrighted Material
Chapter 9
Indeed. And now
we cn
deine
the
visitor
49
HasPtv, whose methods determine whether
some Shapev hs a PointV inside of it.
The three methods put into algebra what we
just discussed.
clss HasPt v implements ShapeVisitoI {
PointV p;
HasPtv (PointV _p) {
p
-p; }
=
}
public boolean forCircle(int r) {
return p.distanceToOO ; r; }
public boolean forSquare(int s) {
if! (p.x ; s)
return (p.y ; s);
else
return false; }
public
boolean forTans(PointV q,Shapev s) {
return s.accept(
new HasPtV(p.minus(q))); }
We could have written the if
retn (p.x <=
50
What is the value of
new Circle(lO)
. accept (
new HasPtV(new CatesianPt(lO,lO)))?
.
.. s
&& (p.y <= s).
We said that this point wsn't inside of that
circle, so the answer
51
Good. And what is the value of
s)
is false.
true.
new Square(lO)
.accept(
new HasPtV (new CatesianPt(lO,lO)))?
Let's consider something
interesting. What
is
a
bit
more
the value of
new Trans(
new CatesianPt(5,6),
new Circle(lO))
. accept (
new HasPtV(new CatesianPt(lO,lO)))?
Be
a
Good Visitor
52
We already considered that one, too. The
value is true, because the
new CatesianPt(5,6).
Copyrighted Material
circle's orig i n is at
147
how about this:
new Trans(
new CatesianPt(5,4),
new Trans(
new CartesianPt(5,6),
new Circle(lO)))
. accept (
new Ha sPt V (new CartesianPt(lO,lO)))?
Right. And
53
Trans
twice,
which we should have expected given
Trans's
deinition.
54
But what is the value?
Now that is t ricky. We used
First, we have to ind out whether
new Trans(
new
CatesianPt(5,6),
new Circle(lO))
. accept (
is
55
And then?
new HasPtV(new CatesianPt(5,6)))
true
or
fa Ise.
Secon d , we need to look at
new Circle(lO)
. accept (
new
H asPtV ( new
CatesianPt(O,O))),
true.
but the value of this is obviously
Very good. Can we nest
Trans three
ti mes?
56
Ten times, if we wish, because
contains a
ShapeD,
things s ot en
57
Ready to begin?
No. The exciting part is about to start.
How
can
we proj ect
piece of paper?
a
cube of cheese to a
And the orange on top?
148
58
59
60
s
a
Trans
and that all ows us to nest
needed.
What? Wsn't that it?
We are all eyes.
It becomes a square, obviously.
A circle,
Copyrighted Material
Transed
appropriately.
Chapter 9
Can we think of the two objects s one?
61
We can, but we have no way of saying that a
circle and a square belong together.
62
Here is our way.
That looks obvious ater the fact. But why is
there a blank in
accept?
We know that a
ShapeVisitox contains one
Circle, Square, and Trans
class Union extends Shapev {
Shapev s;
Shapev t;
Union(ShapeV _s,Shapev _t) {
s _s;
t _t; }
=
=
}
boolean accept(ShapeVisitox ask) {
return
; }
What do we know rom
Trans
about
Circle, Square,
and
63
accept?
method each for the
variants. And each of these methods
consumes the ields of the respective kinds of
objects.
6.
So what should we do now?
We need to change
ShapeVisitox so that it
Union variant in
speciies a method for the
addition to the methods for the existing
variants.
Correct, except that we won't allow ourselves
to change
a
Why can't we change
it?
ShapeVisitox
Just to make the problem more interesting.
Be
65
Good Visitor
66
In that cse, we're stuck.
Copyrighted Material
149
We would be stuck, but fortunately we can
extend
interfaces.
67
Which means that we extend
interfaces
the
way we extend clsses.
Take a look at this.
interface UnionVisitox
extends ShapeV isitox {
boolean forUnion(ShapeD s,ShapeD t);
}
Bsically.
1
68
This extension produces an
(i. e.,
for Union
names of methods and what they
)
ShapeV is itox
named for Union.
consume and produce of
the additional one
Does that mean
accept
,
in
Union
should
receive a U n ionV i sitox so that it can use the
interface that contains all the obligations
method?
and
1 Unlike a clss, an interfce can ctually extend severa1
other interfces. A clss can implement several diferent
interfces.
Yes it should, but because
ShapeV is itox ,
S hapeV isitox .
extends
UnionVisitox
69
a
fortunately every
S hapeV isito,x too. But if we know that
accept
,
and invoke
Perfect resoning. Here is the completed
Union.
70
UnionV is ito x , we can
ShapeVisitox to a UnionVisitox
the for Union method.
consumes a
convert the
deinition of
accept
ShapeVisitox and
UnionVisitox implements a
We have been here before. Our
method must consume
it is also a
And it makes complete sense.
class Union extends ShapeD {
ShapeD s ;
ShapeD t;
U n ion (ShapeD _s,ShapeD t ) {
}
_
s
=
t
=
_
s;
_t; }
boolean acce pt(ShapeVisitox ask) {
return
((UnionVisitox) ask ).forUnion( s, t); }
150
Copyrighted Material
Chapter 9
Let's create a
Union
71
shape.
That '8 trivial.
new Trans(
new CartesianPt(12,2),
new Union(
new Square(10),
new Trans(
new CatesianPt(4,4),
new Circle(5)))).
That's an interesting shape. Should we check
72
whether
HasPtV is only
UnionVisito�.
We can't.
is not a
ShapeVisito�,
a
it
new CatesianPt(12,16)
is inside?
Could it be a
Deine
73
UnionVisito�?
UnionHasPtV,
which extends
with an appropriate method
No. It does not provide the method
forUnion.
HasPtV
74
forUnion.
Here it is. Its method checks whether the
point is in one or the other part of a union.
The other methods come from
HasPt v
class UnionHasPtV extends HasPtV {
UnionHasPtV(PointD -p) {
super ( _p) ; }
boolean forUnion(ShapeD s , Sha peD t) {
if! ( s. accept (this))
return true;
else
return t.accept(this); }
}
We could have ritten the if
return s.accept(this)
Does
UnionHasPtV
a
Good Visitor
Be
contain
for Union?
75
II
. ..
s
t.accept(this).
Of course, we just put it in.
Copyrighted Material
151
Is
UnionHasPtV
a
�
UnionVisitorr?
It provides the required
forSquare, forrans,
Correct, but unfortunately we have to add
77
three more words to make this explicit.
methods: forCirc le,
forUnion.
and
The irst two additional words have an
obvious meaning. They explicitly say that
this visitor provides the services of
clss UnionHasPtV
extends HasPtV
implements UnionVisitorr {
UnionHasPtV(PointD -p) {
super(_p); }
public
boolean
UnionVisitor.
And,
s
we have said before,
public is necessry, because
this visitor implements an interface.
the addition of
forUnion(ShapeD s,ShapeD t) {
if (s.accept(this))
return true;
else
return t.accept(this); }
}
Good try. Let's see whether it works. What
78
We know how
for ans works, so we're really
sking whether
should be the alue of
new Trans(
new CartesianPt(3,7),
new Union(
new Square(10),
new Circle(10)))
accept (
new UnionHasPtV(
new CatesianPt(13,17)))?
is
new CatesianPt(lO,lO)
inside the Union shape.
.
So?
79
Which means that we're sking whether
new CatesianPt(lO,lO)
is inside of
new Square(10)
or inside of
new Circle{lO).
152
Cophted Maeial
Chapter 9
Okay. And what should be the answer?
80
81
Let's see whether the value of
new
.
Trans(
new CatesianPt(3,7),
new Union(
new Square(lO),
new Circle(lO)))
accept(
new UnionHasPtV(
new CatesianPt(13,17)))
It should be
true.
Usually we start by determining what kind of
object we are working with.
is true?
82
And?
8
3
How did we construct this shape?
Which method should we use on it?
Where is
for rans
deined?
So what should we do now?
84
8
5
86
It's a
ShapeD
With
Trans.
forrans,
of course.
It is deined in
HasPtV
We should determine the value of
new
Union(
Square(lO),
new Circle(lO))
. accept(
new HasPtV(
new CatesianPt(lO,lO))).
new
What type of object is
new
87
It's a
ShapeD.
Union(
new Square(lO),
new Circle(lO))?
Be
a
Good Visitor
Copyrighted Material
153
How did we construct this
ShapeD?
So which method should we use on it?
How do we ind the appropriate jorUnion
88
89
90
With
Union.
jorUnion, of course.
In
accept,
which is deined in
Union,
we
conirm that
method?
new
HasPtV(
new Cates i anPt ( lO, lO ) )
is a
UnionVisitor
jorUnion.
Is an instance of
HasPtV
a
UnionVisitor?
91
and then invoke its
No!
Does it contain a method jorUnion?
92
No!
Then what is the value of
93
It doesn't have a value. We are stuck. 1
new
Union(
new
Square(lO),
Cir cl e( lO ) )
. accept (
1 A Java program raises a Rntimexception1 indicating
that the attempt to conirm the UnionVisitorlness of the
new
object failed. More speciically, we would see the following
when running the program:
java. lng . ClassCastxception:
new
HasPtV(
new CartesianPt(lO,lO)))?
UnionHasPtV
at Union.accept( ... java:.,.)
at UnionHasPtV.forTrns('
java: ... )
at Trns. accept ( .. java: ... )
.
9.
What do we do next?
95
Which of those is best?
We should have prepared this extension in a
better way.
154
96
..
.
Relax. Read a novel. Take a nap.
You guessed it: whatever you did is best.
How could we have done that?
Copyrighted Material
Chapter
9
Here is the deinition of
HasPtV
that we
97
should have provide d if we wanted to extend
In two ways. First, it contai n s
method:
method
it without making changes.
a
new
newHasPt. Second, it uses the new
in place of new HasPtV in forrans.
class HasPtV implements ShapeVisitox {
PointD p;
HasPtV(PointD -p) {
p -p; }
ShapeVisitox newHasPt(PointD p) {
return new HasPtV(p); }
=
I
I
public boolean forCircle(int r ) {
return p.distanceToOO :; r; }
public boolean forSquare(int s) {
ifl (p. x :; s)
return (p.y :; s);
else
return false; }
public
boolean forrans(PointJ q,ShapeJ s) {
return
s. accept(newHasPt(p. minus(q))); }
}
How does this deinition difer from the
previous one?
Good. What does
newHasPt
produce?
And how does it produce that?
Is
newHasPt
like a constructor?
98
99
100
A
new
ShapeVisitorI,
By constructing a
s
new
its i nterface implies .
instance of
HasPtv
It is virtually i ndistinguishable from a
constructor, which is why it is above the line
that separates constructors from methods.
Be
a
Good Visitor
Copyrighted Material
155
Does that mean the new deinition of HasPt v
and the previous one are really the same?l
101
They are mostly indistinguishable. Both
forranses, the one in the previous and the
one in the new deinition of HasPt v, produce
the same values when they consume the
I A functional prorammer would say that newHasPt and
HasPtV are ]-equivalent.
same values.
102
Very well. But how does that help us with
That's not obvious.
our problem?
Can we override
newHasPt when
103
we extend
HasPtv?
Yes, we can override any method that we
wish to override.
104
Let's override newHasPi in UnionHasPtV
That's true. Should it produce a HasPtV or
When we override it, we need to make sure it
produces
a
105
a
ShapeVisito�
The latter. Then for rans in HasPtV keeps
producing a UnionHasPtV, if we start with a
UnionHasPtv?
Uni onHas Ptv
Good answer. Should
we
repeat it?
106
The Ninth Bit
'
Let s just reread·It.
of
Advice
If a datatype may have to be extended,
be forward looking and use a
constructor-like (overridable) method
so that visitors can be extended, too.
156
Copyrighted Material
Chapter 9
And that's exactly what we need. Revise the
deinition of
1
UnionHasPtV.1
The s an istance of the
factoy method
107
Here it is.
---,
class UnionHasPtV
extends HasPtv
implements UnionVisitor {
UnionHasPtV(PointD -p) {
super(_p); }
ShapeVisitor newHasPt(PointD p) {
return new UnionHasPtV(p); }
pattern
}
[4].
If we ssemble all this into one picture, what
108
public
boolean jorUnion(ShapeD s,ShapeD t) {
if ( s. accept(this))
return true;
else
return t.accept(this); }
A drawing that helps our understanding of
the relationships among the clsses and
do we get?
interfaces.
accept
- ShapeVisitor
accept
W hat does the box mean?
109
Everything outside of the box is what we
designed originally and considered to be
unchangeable; everything inside is our
extension.
Be
a
Good Visitor
Copyrighted Material
157
Does the picture convey the key idea of this
110
chapter?
No. It does not show the addition of a
constructor-like method to
it is overridden in
111
Is anything missing?
Let's see whether this deinition works.
112
new
Trans(
new CartesianPt(3,7),
but that's oay.
We remember that the shape ws built with
Union(
new
Square(lO),
Circle(lO)))
new
.
and how
Trans.
What is the value of
new
Square,
HasPtV
UnionHasPt v .
accept(
new
UnionHasPtV(
CatesianPt(13,17)))?
new
Which method should we use on it?
Where is
forrans
deined?
So what should we do now?
113
11.
115
for rans
,
of course.
It is deined in
HasPt v
We should determine the value of
new
Union(
new
Square(lO),
Circle(lO))
. accept(
new
this. newHasPt(
new
What is this?
And how does that work?
116
117
CartesianPt(lO,lO))).
The current visitor, of course.
We determine the value of
this. newHasPt(
new
CatesianPt(lO,lO))
and then use
158
Copyrighted Material
accept
for the rest.
Chapter
9
118
And what do we create?
The new UnionVisitorI:
new Un ionH asPt V (
new
119
What is the value of
new
Union(
new S qu a re ( 10) ,
new Circle(10))
. accept (
new Uni on H asPt V (
new CartesianPt(1O,10)))?
Ca tes ianPt ( 10 , 10)).
UnionHasPt v also satisies the interface
ShapeVisitor", so now we can invoke the
forUnion method.
120
How do we do that?
We irst determine the value of
new
If
Is it
121
true?
Square(10)
. accept (
new UnionH asPt V (
new CatesianPt(10,10))).
it is true, we're done.
It is. So we're done and we got the value we
expected.
122
Are we happy now?
Is it good to have extensible deinitions?
123
Ecstatic.
Yes. People should use extensible deinitions
if they want their code to be used more than
once.
Very well. Does this mean we can put
124
Yes, we can and should always do so.
together lexible and extensible deinitions if
we use visitor protocols with these
constructor-like methods?
And why is that?
Are you hungry yet?
Be
a
Good Visitor
125
126
Because no program is ever inished.
Are our meals ever inished?
Copyrighted Material
159
@o
�) '�
�
i�� � @�
:·
l
111,'
11
I
Copyrighted Material
d
I
Have you ever wondered where the pizza pies
1
You should have, because someone needs to
make the pie.
come from?
2
Here is our pizza pieman.
This is beyond anything we have seen before.
class PiemanM implements PiemanI {
Piev p = new BotO;
public int addTop (0 bject t) {
p new Top(t,p)
=
return occTop(t); }
public int remTop(Object t) {
P
(PieV)p.accept(new RemV(t»
=
return occTop(t); }
public int substTop(Object n,Object 0) {
p = (PieV)p.accept(new SubstV(n,o»
return occTop(n); }
public int occTop(Object 0) {
return
}
M
((Integer)p.accept(new Occursv (0»)
.intValueO; }
This superscript is a
reminder
that the clss mans a
data structure. Lower superscripts when you enter this kind
of deinition in a ile: PiemM.
How so? Haven't we seen
Piev, Top,
and
Bot
3
We have seen t hem.
before?
And haven't we seen visitors like
SubstV,
and
Occursv
Yes, es. But what are the stand-alone
Rem v,
semicolons about?
for various datatypes?
Let's not worry about them for
The State of Things to Come
a
while.
5
Fine, but t hey are weird.
Copyrighted Material
161
Here is the
interface for PiemanM
6
Isn't it missing
p?
interface PiemanI {
int addTop(Object t)j
int remTop (Object t)j
int substTop(Object n,Object o)j
int occTop(Object o)j
}
We don't speciy ields in interfaces. And in
7
W hatever.
any cse, we don't want anybody else to
see p.
Here are
PieVisitor
and
PieD
They are very familiar.
interface PieVisitor {
Object forBot()j
Object forTop (Object t, PieD r);
}
class Bot extends PieD {
Object accept ( PieVisitor ask) {
return ask.forBot()j }
}
abstract class PieD {
abstract
Object accept ( PieVisitor ask);
}
clss Top extends PieD {
Object tj
PieD r;
Top(Object _t,PieD _r) {
t = _tj
r = _rj }
Deine
Bot
and
Top.
Object accept( PieVisitor ask) {
return ask. forTop (t, r) j }
}
Chapter 10
162
Copyrighted Material
Here is
Occurs V.
And this little visitor substitutes one good
It counts how often some
topping for another.
topping occurs on a pie.
class Subst v implements PieVisitoI {
Object n;
Object 0;
SubstV(Object _n,Object 0 ) {
n = n;
0 = 0; }
clss Occursv implements PieVisitoI {
Object a;
OccursV(Object _a ) {
a = a; }
_
_
_
public Object forBotO {
return new Integer(O); }
public Object forTop(Object t,PieV r) {
if (t. equals ( a ) )
return
new Integer(((lnteger)
(r. accept (this)))
.intValueO
+ 1);
else
return r.accept(this); }
_
public Object forBotO {
return new BotO; }
public O bject forTop(Object t,PieV r) {
if ( o. equals (t ) )
return
new Top(n,(PieV)r.accept(this));
else
return
new Top(t,(PieV)r.accept(this)); }
}
}
Great! Now we have almost all the visitors
for our pieman. Deine
Rem v,
a topping rom a pie.
which removes
10
We remember that one, too.
class Rem v implements PieVisitoI {
Object 0;
Rem v (Object 0 ) {
0 = _0; }
_
public Object forBotO {
return new Bot(); }
public Object forTop(Object t,PieV r) {
if ( o. equals (t ) )
return r. accept(this);
else
return
new Top(t,(PieV)r.accept(this)); }
}
The State
of Things
to Come
Copyrighted Material
163
Now we are ready to talk. What is the value
11
of
We irst create a
PiemanM
and then sk how
many anchovies occur on the pie.
new PiemanMO.occTop(new Anchovy())?
12
Which pie?
And how many anchovies are on that pie?
13
14
And what is the value of
15
PiemanM.
That's where those stand-alone semicolons
Yes, we must understand that. There is no
x
we must understand what
=
in the new
None.
number
new PiemanM O.addTop(new Anchovy()),
p
p
come in again. They were never explained.
new PiemanMO.addTop(new Anchovy())?
rue. I f we wish t o determine the value of
The pie named
=
x
x
in the world for which
+ 1,
so why should we expect there to be a Java p
new Top(new AnchovyO,p)
such that
return occTop(new Anchovy())
p
=
new Top(new Anchovy(),p)?
means?
That's right. But that's what happens when
16
So what does it mean?
you have one too many double espressos.
Here it means that
references to
p
p
changes and that future
17
And the change is that
p
hs a new topping,
right?
relect the change.
IS
When does the future begin?
Does it begin below the stand-alone
semicolon?
That's precisely what a stand-alone
19
It produces the number of anchovies on p.
semicolon means. Now do we know what
return occTop(new Anchovy())
produces?
164
Chapter 10
Copyrighted Material
20
And how many are there?
21
And now what is the value of
We added one, so the value is 1.
It's
2,
isn't it?
new PiemanMO.addTop (new Anchovy ())?
No, it's not. Take a close look. We created a
new
22
pieman, and that pieman added only
one anchoy to his
p.
23
Yes, there is. Take a look at this:
PiemanL y
=
Oh, isn't there a way to place several
requests with the same pieman?
Oay,
y
stands for some pieman.
new PiemanMO.
24
What is the value of
1.
We know that.
y.addTop (new AnchovyO)?
25
And now what is the value of
Still 1. According to the rules of semicolon
and
y. substTop (new TunaO,new Anchovy ())?
=,
this replaces all anchovies on
26
Very good. And now take a look at this:
=
0, because
y
'
s pie no longer contains any
anchovies.
y.occTop(new Anchovy ())?
PiemanL yy
with
p.
tuns are on
Correct. So what is the value of
p
tuns, changes p, and then counts how many
27
What are the
new PiemanMO.
What is the value of
doing at the end?
yy.addTop (new Anchovy ())
,
yy.addTop (new Anchovy ())
,
yy.addTop (new Salmon ())
The State of Things to Come
Copyrighted Material
165
Because this is only half of what we w ant to
28
look at. Here is the other half:
4. First we add two anchovies, then a
salmon, and two tuns.
yy.addTop(new Tuna ( ) )
Th en
we substitute
the two anchovies by two tuns. So y y ' s pie
co ntai ns four tuns.
yy.addTop(new Tuna ())
yy.substTop(new TunaO,new Anchovy ( )) ?
29
And what is the value of
yy.remTop(new Tuna ( ))
It's 0, because emTop irst
r e moves
all tuns
and then counts how many there are let.
ater we are through with all that ?
Does that mean
rem Top
always produ ces
O?
Now what is the value of
30
Yes, it alw ays does .
31
1.
32
0,
33
No, it chnged.
yy.occTop(new SalmonO)?
And how about
b ec aus e
y nd yy are two diferent piemen.
y.occTop(new Salmon ( )) ?
Is yy the same pieman
s
before?
34
So is it the same on e?
When we eat a pizza pie ,
e
chang e , but we
are still the same .
When we sked yy to substitute all anchovies
35
The p in yy changed , nothing else.
by tunas, did the pie change?
Does that mean that anybody can w rite
yy.p
=
new Bot O
and thus change a pieman like yy?
166
36
No, because y y ' s type is PiemanI, p isn't
available. Only addTop, remTop, substTop,
and oce Top are visible.
Copyrighted Mateial
Chapter 10
Isn't it good that we didn't include
p
in
37
PiemanI?
Yes, with this trick we can prevent others
from changing p
38
Clear like soup?
Cn we deine a diferent version of Subst V so
39
( or
Everything is
ways.
•
parts
of p)
in strange
clear now.
•
Just hke chIcken soup.
We can't do that yet.
that it changes toppings the way a pieman
changes his pies?
And that's what we discuss
next.
Do you
40
No, a cup of cofee will do.
need a break?
Compare this new
PieVisitorI
with the irst
41
one in this chapter.
still provide two methods:
for-Top,
rue. Here is the unchanged datatype.
42
the
Bot
Bot
and the latter
a
Top.
deinition is straightforward.
variant.
Is it? Why does it use
this?
43
We only have one instance of
use
State of Things to Come
Bot when we
this, so fo-Bot is clearly
to consume this.
fo-Bot,
supposed
The
a
class Bot extends PieD {
Object accept(PieVisito� ask) {
return ask.for-Bot(this); }
}
abstract class PieD {
abstract
Object accept(PieVisitorI ask);
}
Deine
The
must
except that the former now
consumes
interface PieVisito� {
Object fo-Bot(Bot that);
Object fo-Top(Top that);
}
PieVisitorI
fo-Bot and
It isn't all that diferent. A
Copyrighted Material
namely
167
That's progress. And that's what happens in
Top,
44
Interesting.
too.
class Top extends PieD {
Object tj
PieD r;
Top(O bject _t,PieJ _r) {
t
t;
r = _rj }
=
_
Object accept(PieVisitox a sk) {
return ask.forTop(this); }
}
Modiy this
version of
implements
the new
Occurs v so that
PieVisitox
it
45
method bsically stays the same,
changes somewhat.
clss Occursv implements PieVisitox {
Object a;
Occursv (Object _a) {
a _a; }
_
=
public O bj ec t forBot(Bot that) {
return new Integer(O)j }
public Object forTop(Top that) {
if ( th at. t. equals ( a))
ret urn
new Integer«(lnteger)
(that. r. accept(this)))
. int Value 0
+ 1)j
else
return that. r. accept (this); }
public Object forBotO {
return new Integer(O); }
public O bject forTop(O bject t,PieD r) {
if (t. equals ( a) )
return
new I ntege r ( «Integer)
( r. ac cept (this) ))
. intValue 0
+ 1);
else
return r.accept(this); }
}
How does
forBot
but forTop
class Occursv implements PieVisitox {
O bject aj
OccursV(Object _a) {
a
a; }
=
The
}
forBot
change?
46
It now consumes a Bo t , which is why we had
to
add (Bot that)
168
Copyrighted Material
behind its name.
Chapter 10
How does
JorTop
47
change?
It
no
longer receives the ield
v
alues of the
corresponding Top. Instead it consumes the
entire object, which makes the
available
48
And?
49
Then try
50
Rem v
that. t
and
that. r.
With that, we can replace t he
with
Isn't that esy?
s
that. t
and
that. r.
This modiication
of
Occursv
two ields
ields t and
certainly
r
is.
It's esy; we use the same trick.
clss Rem v implements PieVisito" {
Object 0;
RemV(Object _0) {
0= _0; }
public Object JorBot(Bot that) {
return new Bot(); }
public Object JorTop(Top that) {
if (0. equals ( that.t))
return that.r.accept(this)j
else
return
new Top(that.t,
(PieD)that.r.accept(this)); }
}
Do we need to do
And
indeed, it
51
SubstV?
52
is. Happy now?
So far, so good. But what's
the
Remv.
point of this
exercise?
Oh, PointDs? They will show up later.
The State of Things to Come
Not really. It should be just like
53
Seriously.
Copyrighted Material
169
Here is the point. What is new about this
version of
54
There are no
Substv?
news.
class SubstV implements PieVisitox {
Object n;
Object 0;
SubstV (Object _n,Object _0) {
n = _n;
0= _0; }
public Object JorBot (Bot that) {
return that; }
public Object JorTop (Top that) {
if ( o. equals (that. t)) {
that.t
n
=
that. r. accept ( this)
return that; }
else {
that. r. accept ( this)
return that; }
}
}
Don't they say "no
news
is good news?"
Yes, because we want to deine a version of
SubstV
55
56
•
•
Does thIS saymg apply here, too?
That's a way of putting it.
that modiies toppings without
constructing a
new
pie.
What do the methods of
Substv
always
57
return?
They always return
that,
which is the object
that they consume.
So how do they substitute toppings?
58
By changing the
that
before they return it.
Speciically, they change the
n
170
when it equals
Copyrighted Material
t
ield of
that
to
o.
Chapter 10
59
What?
The
that.t
=
n
does it.
Correct. And from here on,
that. t
holds the
60
new topping. What is
In the previous
created a
new
Su bstV, r.accept(this)
r with all toppings
pie rom
appropriately substituted. In our new
that. r. accept(this)
version,
about?
that.r.accept(this)
modiies the pie
r
so that below the following semicolon it
contains the appropriate toppings.
Is there anthing else to say about the new
61
Not really. It does what it does, which is
what we wanted. 1
Su bstv?
1 This is a true instance of the vlitor pattern
[41.
What we
previously called ('visitor" pattern instances, were simple
variations on the theme.
Do we have to change
62
PiemanM?
we only changed how they do things.
Is it truly safe to modiy the toppings of a
63
pie?
Yes, because the
toppings of
LtdSu bstV now w ithout creating
instances of LtdSubstV or Top?
Can we do
new
No, we didn't change what the visitors do,
64
p,
PiemanM
manages the
and nobody else sees
p.
Now that's a piece of pie.
The Tenth Bit of Advice
hen modiications to objects are
needed, use a class to insulate the
operations that modify objects.
Otherwise, beware the consequences of
your actions.
The State of Things to Come
Copyrighted Material
171
Here is a true dessert. It will help us
65
understand what the point of state is.
The datatype hs three extensions.
class CatesianPt extends PointV {
CartesianPt(int x ,int _y) {
super(_x,_y); }
abstract class PointV {
int x;
int y;
PointV(int _x,int _y) {
x = -x;
y -y; }
=
}
boolean closerToO(PointV p) {
return
distanceToOO S p.distanceToOO; }
PointV minus(PointV p) {
return
new CatesianPt(x - p.x,y - p.y); }
abstract int distanceToOO;
int distanceToOO {
return l Jx 2 + y2J; }
class ManhattanPt extends PointV {
ManhattanPt(int _x,int _y) {
super(_x,_y); }
int distanceToOO {
return x + y; }
}
}
class ShadowedManhattanPt
extends ManhattanPt {
int .x;
int .y;
ShadowedManhattanPt(int -x,
int _y,
int _.x,
int _.y) {
super(_x,_y);
.x _.x;
.y _.y; }
=
=
int distanceToOO {
return
super.distanceToOO+.x + .y; }
}
Aren't we missing a variant?
172
66
Yes, we are missing
Copyrighted Material
ShadowedCatesianPt.
Chapter 10
Good enough. We won't need it. Here is one
67
point:
Shouldn't we add a method that changes all
the ields of the points?
new ManhattanPt(1,4).
If this point represents a child walking down
the streets of Manhattan, how do we
represent his movement?
Yes.
Add
to
PointV
the method moveBy,
68
First we must know what the method is
supposed to produce.
which consumes two ints and changes the
ields of a point appropriately.
The method should return the new distance
69
to the origin.
Now we know how to do this.
abstract class PointV {
int xii
int Yi
PointV (int _x,int _y) {
x
= -Xj
Y = -Yi }
boolean closerToO(PointV p) {
return
distanceToOO S p.distanceToOOi }
PointV minus(PointV p) {
return
new CatesianPt(x - p.x,y - P.Y)i }
int moveBy(int �x,int �y) {
x = x
+ �x
,
return distanceToOO; }
abstract int distanceToOOj
}
ptChild stand for
new ManhattanPt(1,4).
Let
70
5.
What is the value of
ptChild. distance ToOO?
The State
of
Things
to Come
Copyrighted Material
173
71
What is the value of
15.
ptChild.moveBy(2,8)?
Good. Now let's watch a child with a
72
7.
helium-illed balloon that csts a shadow.
ptChildBalloon be
new ShadowedManhattanPt(I,4,I,I).
Let
What is the value of
ptChildBalloon. distance To 0 O?
73
What is the value of
17, of course.
ptChildBalloon. moveBy(2,8)?
74
Did the balloon move, too?
Yes, it just moved along
s
we moved the
point.
75
Isn't that powerful?
It
sure is. We added one method, used it,
and everthing moved.
The more things change, the cheaper our
76
Yes, but to get to the dessert, we had to
work quite hard.
desserts get.
Correct but now we are through and it is
77
Don't forget to leave a tip.
time to go out and to celebrate with a grand
dinner.
174
Copyrighted Material
Chapter 10
Copyrighted Material
You have reached the end of your introduction to computation with clsses, interfaces, and
objects. Are you now ready to tackle a major programming problem? Programming requires
two kinds of knowledge: understanding the nature of computation, and discovering the lexicon,
features, nd idiosyncrsies of a particular programming language. The irst of these is the more
diicult intellectual tsk. If you understand the material in this book, you have mstered that
challenge. Still, it would be well worth your time to develop a fuller understanding of all the
capabilities in Java-this requires getting access to a running Java system and mstering those
idiosyncrsies.
If you want to understand Java and object-oriented systems in greater depth,
take a look at the following books:
References
1. Arnold and Gosling.
The Java Pogamming Language . Addison-Wesley, Reading, Ms­
sachusetts, 1996.
2. Buschmann, Meunier, Rohnert, Sommerlad, and Stal.
A System of Pattens: Patten­
Orie n ted Sotware Architecture. John Wiley & Sons, Ltd. Chichester, Europe, 1996.
3. Firesmith and Eykholt .
Dictionary of Object Technolog y . SIGS Books, Inc., New York,
New York, 1995 and Prentice Hall, Englewood Clifs, New Jersey, 1995.
4. Gamma, Helm, Johnson, and Vlissides.
Design Patterns.
Addison-Wesley, Reading,
M ssachusett s , 1994.
5. Gosling, Joy, and Steele.
The Java Language Speciication.
Addison-Wesley, Reading,
Mssachusetts, 1996.
6. Pree. De sign Pattens for Object-Oriented Sotware Development. Addison-Wesley, Read­
ing, Mssachusetts, 1994.
Commencement
Copyrighted Material
177
Index
Add, 124
iO ccursv ,
161
addTop,
IsFlat v,
43, 53, 64, 65, 69, 72
Anchovy,
IsSplit v, 113
App le, 100
is Vegetaian, 25, 27
IsVegetarian v, 63
Base, 10
bHasFruit V,
is Veggie, 30, 31, 36
104
Brass, 29
LtdSubstV, 95,97,132-136
CartesianPt, 5,13,37, 38-40, 139,172
43,53, 64, 65
closerToO, 14,38-40,139,172,173
119
C op p er, 29
moveBy, 173
NumD, 7,79
Dagger, 29
ace
dif, 124
161
Top,
Occursv ,
Diff, 119
distance ToO, 14,38-40, 139, 141, 142,172
Empty, 124
equals, 72, 79, 100
130
ExprD, 119
ExprVisito�, 118
69,72
Flat, 100, 101, 108,110, 112
F ru itD , 100
114,163,168
43, 53, 64, 65
Olive,
O n e M ore Than,
Onion,
7,79
16, 27, 28, 36, 59, 62
onlyOnions, 18, 27
OnlyOnionsv, 57, 59
Peach,
Pear,
100
100
Pepper,
100
FishD,
minus, 139
newHasPt, 155, 157
Crust , 43, 53, 64, 65
Fig ,
ManhattanPt, 5, 13,38,39,139, 172
mem,124
Circle, 143
EvalD,
Lamb, 16, 27, 28, 36, 59, 62
LayerD, 10
Lemon, 100
Bud, 100, 101, 107, 110,112
bTreeVisito�, 101
Const,
28, 36
KebabD,
102, 103
Bot, 69, 78, 83, 85,86, 91,93, 162, 167
Cheese,
107
iTreeVisito�,
blsFlatV, 102
blsSplit v,
111
113
PieD ,
4, 37
69,78,83,85,86,91,93,162, 167
PieVisito�,
PiemanT,
92,162, 167
162
PiemanM , 161
Gold, 29
P izzaD , 43, 53, 63-65
H asP tV , 147,155
plus, 124
H ol d er, 28, 36
Plus,
PlateD,
iHeightV, 108
IntEvalv,
120,122,131
29
119
PointD, 5, 13, 40, 139, 172, 173
pod, 124
Prod,
Copyrighted Material
119
Radish, 28, 36
subAbC, 52, 53
remA, 45, 49, 70
SubAbCv, 66
RemAv,
SubstV,
66,71,73
133, 134
RemFishv, 74
SubstFish v,
Remv,
SubstV, 83,87,89,94,132-136,163,170
77,87,93,163,169
SubstlntV, 82
RemlntV, 76
161
remTop,
substTop, 161
29
Rodv,
Sword, 29
Sabre, 29
Thyme,
Sage,
Tomato,
5
Salmon,
Salt,
TopAwCv, 66
43, 53, 63-65
SeasoningV,
4
123
ShadowedCartesianPt,
141, 142
ShadowedManhattanPt,
S hallot ,
28, 36
Shapev,
143
139, 172
ShapeVisito�. 144
Shishv, 16,27,59,61
Shrimp, 28, 36
Silver, 29
Skewer,
16, 27, 59, 62
Slice, 10
Spinach,
54
100, 101 , 108, 110 , 112
Square,
143
Trans,
144
Treev.
100, 101, 107, 109, 112
T reeVisito� .
SetEvalv, 126, 131
Index
16, 27, 28, 36, 59, 62
topAwC, 50, 53
4
Split,
5
Top, 69, 78, 83, 85, 86, 91, 93, 162 168
69, 72
Sausag e,
SetV,
82
tSubstV,
tTreeVisito�,
Tuna,
112
111
109
69,72
Union, 149. 150
UnionHasPtv,
151, 152, 157
UnionVisito�,
150
whatHolder, 33-36
Wood,
29
Zero, 7, 79
Zucchini,
Copyrighted Material
37,
179
This is for the loyal Schemers and MLers.
TI {
o >oI apply(TI x);
No, we wouldn't forget factorial.
MkFact implements oo>ooI {
public O>OI apply( o>oI fact) {
return ne w Fac t (fact ); }
interface
class
}
}
interface O> oI {
Object apply(Object x);
class Fact
implements
o>oI fact;
Fact(o>oI _fact) {
fact
-fact; }
}
o>oI {
=
oo>ooI {
o > oI apply ( o>oI x);
interface
Object apply(Object i) {
int inti
((lnteger)i).intValue();
if (inti
0)
return new Integer(1);
public
=
}
==
else
oo>oo>ooI {
apply ( oo>ooI x);
interface
O>O
I
return
new
}
Integer(
inti
*
oo>OO>ooI {
public o>oI apply ( oo+ooI J) {
return new H(f).apply(new H(f)); }
((Integer)
fact.apply(new Integer(inti
.intValue()); }
class Y implements
}
}
TI {
f;
H ( oo+ooI -J) {
f -f; }
public o > OI apply(TI x) {
return .apply(new G(x)); }
class H implements
I
OO+OO
=
}
class
G implements o>oI {
TI x;
G(TI _x) {
X
_x; }
=
}
public Object apply ( Object y) {
return (x.apply(x)).apply(y); }
Copyrighted Material
-
1)))
Download