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)))