unit 27 interpreter

147
Unit 27 Interpreter Summary prepared by Kirk Scott 1

Upload: valora

Post on 15-Feb-2016

40 views

Category:

Documents


0 download

DESCRIPTION

Unit 27 Interpreter. Summary prepared by Kirk Scott. Design Patterns in Java Chapter 25 Interpreter. Summary prepared by Kirk Scott. The Introduction Before the Introduction. There are several problems with this chapter Among them are the following: - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Unit 27 Interpreter

1

Unit 27Interpreter

Summary prepared by Kirk Scott

Page 2: Unit 27 Interpreter

2

Design Patterns in JavaChapter 25Interpreter

Summary prepared by Kirk Scott

Page 3: Unit 27 Interpreter

3

The Introduction Before the Introduction

• There are several problems with this chapter• Among them are the following:• 1. The book doesn’t explain the following two points very well:• A. What is an interpreter?• B. Why would you want to use the Interpreter design pattern?• The book touches on these questions in the last subsection of

the chapter• Even then, the book seems to concede that not all of the

machinery is present in order to make this be very practical or seem very practical

Page 4: Unit 27 Interpreter

4

• 2. Another shortcoming is that in implementing the pattern, some of the book’s code is not easy to understand

• This breaks down into two sub-problems• A. The underlying problem seems to me to be

that the code violates encapsulation• Not only is this potentially a poor choice, but

this is part of what makes it hard to understand

Page 5: Unit 27 Interpreter

5

• B. The additional observation on this is that the book’s explanations are not incredibly transparent

• The code is hard to understand, and even after reading the explanations, you’re left wondering whether the book’s approach was a good idea or not

Page 6: Unit 27 Interpreter

6

1.A What is an Interpreter?

• Returning to point 1 in more detail:• In general, in what problem domain do you expect to

hear about interpreters?• The answer is, this belongs in the category of language

processing• In other words, you think of interpreters and compilers

at the same time• These are pieces of code which allow you to translate

from a source language to a target language, from high level code to machine code

Page 7: Unit 27 Interpreter

7

• If you have had a course in programming languages or compilers you might also have heard the terms lexical analyzer and parser

• These terms refer to different steps in reading a source file containing statements in some language, and translating them, ultimately, into a sequence of instructions that can be executed on a computer chip

Page 8: Unit 27 Interpreter

8

• For the sake of background, here is a definition of a lexical analyzer (from Aho, Sethi, and Ullman

• “The lexical analyzer is the first phase of a compiler. Its main task is to read the input characters and produce as output a sequence of tokens that the parser uses for syntax analysis.”

• In other words, given a stream of characters, break it into a sequence of constants, variables, operators, keywords, etc.

Page 9: Unit 27 Interpreter

9

• Here is a definition of a parser (from Aho, Sethi, and Ullman)

• “In our compiler model, the parser obtains a string of tokens from the lexical analyzer, …, and verifies that the string can be generated by the grammar for a source language. We expect the parser to report any syntax errors in an intelligible fashion.”

• In other words, the parser checks to see whether the input, after having been broken into tokens, forms a set of statements in the supposed source language.

Page 10: Unit 27 Interpreter

10

• The last stage in a compiler is translation from the verified statements of the source file to an equivalent sequence of instructions in the target language

• So what’s an interpreter, compared to a compiler?• In very simple terms, an interpreter is a system

that translates each statement as it’s parsed, and executes it without waiting to translate the complete program

Page 11: Unit 27 Interpreter

11

• Interpretation can be a preferred way of dealing with programs for several reasons

• It is common with command languages, for example

• Users may enter ad hoc sequences of instructions at a command prompt

• These instructions may be calls to external applications like system utilities

Page 12: Unit 27 Interpreter

12

• If on the command side, it’s difficult to foresee and impossible to control exactly what results the system utility produces, then a compiler may not be able to form a complete program

• It is better to have an interpreted system that is flexible and responsive to the results that are produced command by command

• In other words, it makes sense to translate one step at a time

Page 13: Unit 27 Interpreter

13

• You may recall that Java is referred to as an interpreted language

• On the other hand, you are also familiar with the idea that you have to compile Java source code

• What’s going on?• A Java source file is written in Java, a high

level, human understandable language

Page 14: Unit 27 Interpreter

14

• Compilation results in a class file, containing what is known as bytecode

• Bytecode is not machine language for any actual physical machine

• It is the language of the Java Virtual Machine• What is the Java Virtual Machine?• In one respect, it is a simulated machine which

runs bytecode

Page 15: Unit 27 Interpreter

15

• In another respect, it is an interpreter• It interprets bytecode, line by line, into code

that can run on the physical host machine• What advantage is there to this overall

design?• Java is “universal”• It can be run on any hardware for which a Java

Virtual Machine exists

Page 16: Unit 27 Interpreter

16

• The code is only compiled once, into bytecode• It is not compiled a second time, into machine

language• When a Java class file is to be run, there is no

delay while it is translated in its entirety into machine language code

• It starts running immediately—running on the machine simulation—running “on” the interpreter which the Java Virtual Machine is

Page 17: Unit 27 Interpreter

17

B. Why Would You Want to Use the Interpreter Design Pattern?

• The book tries to illustrate the Interpreter design pattern in a practical, applied way

• Instead of worrying about the problems of language interpretation, the authors pose the problem of creating programs that interact with and control machines in a factory

• They develop a mechanism that makes it possible to build programs that would have this effect

Page 18: Unit 27 Interpreter

18

• Then at the end of the chapter they observe that you could write programs directly which would control the machines

• It’s not clear that you’ve gained any benefit from the machinery that makes it possible to compose sequences of commands which could be used as machine control programs

• In response to this, they observe the following:

Page 19: Unit 27 Interpreter

19

• It would be possible to have another language, a language for controlling machines, in which a programmer/engineer/person responsible for a machine could write a program to control it

• Such a language would not have to have the features of Java

• It could be restricted to concepts of machine control only

Page 20: Unit 27 Interpreter

20

• Writing machine control programs in such a language would be simpler

• The problem would then become, how to translate them into Java code for use in factory environment where implementations were done in that language

Page 21: Unit 27 Interpreter

21

• The book finally concludes that you would need a parser that could translate from the simple, machine control language, into the machinery for building Java programs which they present as the Interpreter design pattern

• Then the interpreter design pattern as presented here would become useful

Page 22: Unit 27 Interpreter

22

• On the one hand, we can be thankful that the book doesn’t try to complete the job by developing a parser

• On the other hand, it turns out that the motivation for the Interpreter design pattern is incomplete

• We are shown how it’s done, but it’s hard to imagine that it’s very useful when the book concedes that you could just write straight Java code to accomplish all that the examples accomplish

Page 23: Unit 27 Interpreter

23

• In conclusion in this introductory subsection, I can only say this:

• It’s an eternal problem that when you try to explain something complicated, you end up simplifying

• The simplification often makes the example seem pointless

• This doesn’t mean that the design pattern is useless• Regardless of the examples, the goal is to

understand the pattern

Page 24: Unit 27 Interpreter

24

2.A Encapsulation is Violated

• It appears that the authors violate encapsulation in part of their implementation of the Interpreter design pattern

• This will be pointed out specifically in the code when it is presented

• The statement is always made that violating encapsulation is bad

• At the very least, you will see that it makes the code hard to understand

Page 25: Unit 27 Interpreter

25

• The book’s explanations don’t really make it clear• This may lead you to the following, valid conclusion:• Maybe part of the reason that violating

encapsulation is bad is that it leads to code that is hard to understand

• Maybe part of the reason for developing the concept of encapsulation was to try to avoid the difficulties in understanding that become evident when encapsulation is violated

Page 26: Unit 27 Interpreter

26

Introductory Book Material

• The Interpreter design pattern can be used to make objects where the objects, in essence, are like individual commands

• Different kinds of commands are implemented as different classes

• Each of these classes has a method of the same name, something like execute(), and the difference in the command objects consists of the fact that the code for the execute() method differs among the different command classes

Page 27: Unit 27 Interpreter

27

• In general, the Interpreter design pattern can be thought of as supporting multiple commands

• Structurally, the Interpreter pattern is similar to the State and Strategy patterns because each class has the same method

• Recall that in the State example, every door state had a touch method

• In the strategy example, every kind of advisor had a recommend() method

• With the interpreter, each kind of command will have an execute() method

Page 28: Unit 27 Interpreter

28

• The Interpreter design pattern is also closely related to the Composite design pattern

• The Interpreter pattern will be used to create sequences of commands

• Macros or subroutine calls in a program are subsequences of commands

• A complex sequence of commands may consist of single commands as well as composite commands

• A reasonably complete implementation of the Interpreter pattern will track the way things can be put together as individual leaf items, and composite nodes, where each of these is a type of component

Page 29: Unit 27 Interpreter

29

• Book definition:• The intent of the Interpreter pattern is to let

you compose executable objects according to a set of composition rules that you define.

Page 30: Unit 27 Interpreter

30

An Interpreter Example

• The book illustrates the Interpreter design pattern using the robots that transport material between machines and that can load and unload the machines

• The UML diagram on the following overhead shows a Robot class and a small hierarchy of commands

• The command hierarchy is the same in structure as a composite hierarchy

Page 31: Unit 27 Interpreter

31

Page 32: Unit 27 Interpreter

32

• In looking at the UML diagram, the following things should be noticed:

• There is an abstract method, execute(), at the top of the command hierarchy

• It is concretely implemented in the two subclasses• The CommandSequence class also has an add()

method for building up composites• Otherwise, there are no other methods in the

Command hierarchy

Page 33: Unit 27 Interpreter

33

• Also notice that the CarryCommand class has a constructor, which takes two machines as input parameters

• The way a command is set up to work on robots/machines is by constructing it with the necessary references

• There are corresponding instance variables for these references in the CarryCommand class

• You can foresee that the implementation of the execute() method will work by calling the carry() method of the Robot class on these references

Page 34: Unit 27 Interpreter

34

• The next thing to ask is, “So, what part of this design is the interpreter?”

• The answer is, the command hierarchy is in essence the interpreter

• A program, named ShowInterpreter, will be given shortly, which illustrates the use of the hierarchy

Page 35: Unit 27 Interpreter

35

• A bunch of things are assumed in the code, but they’re not difficult

• You obtain a machine composite object for the factory in Dublin, Ireland

• You then obtain references to specific machines

• You then write code to load bins into the machines

Page 36: Unit 27 Interpreter

36

• You then construct two instances of CarryCommand using these machines as input parameters

• You then construct an instance of CommandSequence and add the individual commands

• Finally, you call execute on the sequence object• It is this one, final line of code which controls the

robot/machines in the factory

Page 37: Unit 27 Interpreter

37

• In essence, the whole machine control program has been packaged up in the one object and the one call to the execute() method

• This is what the mean by “composing sequences of instructions”

• The code is given on the next overhead

Page 38: Unit 27 Interpreter

38

• public class ShowInterpreter • {• public static void main(String[] args) • {• MachineComposite dublin = OozinozFactory.dublin();• ShellAssembler assembler = (ShellAssembler)

dublin.find("ShellAssembler:3302");• StarPress press = (StarPress) dublin.find("StarPress:3404");• Fuser fuser = (Fuser) dublin.find("Fuser:3102");

• assembler.load(new Bin(11011));• press.load(new Bin(11015));

• CarryCommand carry1 = new CarryCommand(assembler, fuser);• CarryCommand carry2 = new CarryCommand(press, fuser);

• CommandSequence seq = new CommandSequence();• seq.add(carry1);• seq.add(carry2);

• seq.execute();• }• }

Page 39: Unit 27 Interpreter

39

• Rather than showing the code for the command classes in advance, the book shows it after the example where it is used

• The CommandSequence class has an ArrayList of commands

• The add() method allows commands to be added

Page 40: Unit 27 Interpreter

40

• The execute() method looks like the methods, like isTree(), in the composite design pattern

• It iterates over all of the elements of the ArrayList calling execute() on them

• If the element is a leaf, then the version of execute() in the CarryCommand class is used

• If the element is a composite, then the call is recursive• The code for the CommandSequence class is shown

on the next overhead

Page 41: Unit 27 Interpreter

41

• public class CommandSequence extends Command • {• protected List commands = new ArrayList();

• public void add(Command c) • {• commands.add(c);• }• • public void execute() • {• for (int i = 0; i < commands.size(); i++) {• Command c = (Command) commands.get(i);• c.execute();• }• }• }

Page 42: Unit 27 Interpreter

42

• The CarryCommand class has references to two machines

• It has a constructor that takes two machine references as input parameters

• And it is has an execute() method• The execute() is implemented by making a call to

carry() on the single instance of Robot maintained in the Robot class, passing the machine references as parameters to this method

• The code is shown on the following overhead

Page 43: Unit 27 Interpreter

43

• public class CarryCommand extends Command • {• protected Machine fromMachine;• protected Machine toMachine;

• public CarryCommand(Machine fromMachine, Machine toMachine) • {• this.fromMachine = fromMachine;• this.toMachine = toMachine;• }

• public void execute() • {• Robot.singleton.carry(fromMachine, toMachine);• }• }

Page 44: Unit 27 Interpreter

44

• The next step in developing the Interpreter design pattern is to add more subclasses to the Command hierarchy

• The idea is that each different command type, in its execute() method, will package up a different kind of action that could be taken in controlling machines in a factory

• This expands and generalizes the kind of total program for machine control that the interpreter pattern can generate and package altogether

Page 45: Unit 27 Interpreter

45

• In addition to a CarryCommand, there might be a StartUpCommand and a ShutDownCommand

• In addition to simple commands, there might be commands that reflect the structure of a programming language

• This is where the complexity starts to set in

Page 46: Unit 27 Interpreter

46

• The tree-like structure of the composite makes it possible to simply model macros, namely subsequences of code

• However, a complete programming language allows iteration• The book introduces the idea of a ForCommand into the

Command hierarchy• The ForCommand class implements the logic of a for each

loop• The UML diagram for the expanded interpreter is shown on

the next overhead• Explanations follow

Page 47: Unit 27 Interpreter

47

Page 48: Unit 27 Interpreter

48

• Most of the UML diagram is just a generalization of the previous one—with more Command classes added

• The new aspect of the diagram is the arrow from the ForCommand class to the Command class

• An instance of ForCommand will have a reference to another command

• This other command constitutes the body of the for each loop

Page 49: Unit 27 Interpreter

49

• In general, you might expect a design pattern that starts to mimic the elements of a programming language to need a construct that is like a variable

• The book points out that in particular, something that works like a for each loop depends on a variable

Page 50: Unit 27 Interpreter

50

• The syntax for a simple for each loop was given in Unit 9 of CS 202 with this example:

• for(Cup7 someCup: mycollection)• {• myterminal.println(someCup);• }• mycollection was an ArrayList, for example, and

someCup was a variable local to the loop which referred to the successive elements of mycollection

Page 51: Unit 27 Interpreter

51

• This is an analogous loop for commands as given in the book:

• for(Command c: commands)• {• c.execute();• }

Page 52: Unit 27 Interpreter

52

• The book’s idea is that if you want to set up a for each command, the constructor for the ForCommand class will need to take in 3 parameters:

• 1. A collection of machines, the actual objects to iterate over

• 2. A temporary variable, to hold a reference to each object as it’s iterated over in the loop

• 3. A command, which would be the body of the loop that would be iterated

Page 53: Unit 27 Interpreter

53

• Take the CarryCommand for example again• It was an operation that worked on two

objects• Those objects were machines• When an instance of CarryCommand was

constructed, those two machines were input parameters

Page 54: Unit 27 Interpreter

54

• Analogously, the ForCommand constructor will take in a collection of machines as an input parameter

• The ForCommand object that is constructed will iterate over the machines applying whatever command was also entered as an input parameter when the ForCommand object was constructed

• In order to make the ForCommand logic work, it’s necessary to be able to define a variable that will hold the reference to machine objects

Page 55: Unit 27 Interpreter

55

• For better or worse, adding variables to the interpreter is not trivial

• It will take several overheads to discuss how the book accomplishes that before returning to the question of how the ForCommand is implemented

• The classes needed to include variables are shown in the UML diagram on the following overhead

Page 56: Unit 27 Interpreter

56

Page 57: Unit 27 Interpreter

57

• In the UML diagram there is a hierarchy with the class Term at the top

• Thinking back to the very beginning of the presentation, you can think of a term as being a token, more or less

• In other words, a term is a unit, a word that a programming language deals with

Page 58: Unit 27 Interpreter

58

• In a full scale interpreter there could be many different kinds of terms

• As shown here, there are a minimum• Terms are either constants or variables• Each of the concrete classes, Variable and

Constant, has a constructor

Page 59: Unit 27 Interpreter

59

• The system works with machines• A constant is constructed with a machine as the

input parameter• A variable is constructed with a String as an input

parameter• This String is the name of the variable• A variable also has a Term instance variable• This holds whatever value is assigned to the

variable

Page 60: Unit 27 Interpreter

60

• The Constant class has an equals() method, which tests to see whether two constants are in fact the same machine

• It also has an eval() method which is essentially like a get() method

• It returns whatever machine the constant happens to contain

Page 61: Unit 27 Interpreter

61

• The Variable class has an assign() method• This is of critical importance• Variables don’t make sense without the

assignment operation• The assign() method implements the

assignment operation• This method takes in a term, either a constant or

a variable, and assigns that value to the variable

Page 62: Unit 27 Interpreter

62

• The Variable class has an equals() method, which tests to see whether two variables refer to the same machine

• It also has an eval() method• The eval() method in this class is not the same as a

get() method• It returns a reference to the machine object that the

variable refers to• The code for the Constant and Variable classes is given

on the following overheads

Page 63: Unit 27 Interpreter

63

• public class Constant extends Term • {• protected Machine machine;• public Constant(Machine machine) • {• this.machine = machine;• }• public boolean equals(Object obj) • {• if (obj == this)• return true;

• if (!(obj.getClass() == this.getClass()))• return false;

• Constant that = (Constant) obj;• return this.machine.equals(that.machine);• }

Page 64: Unit 27 Interpreter

64

• public int hashCode() • {• return machine.hashCode();• }• public Machine eval() • {• return machine;• }• public String toString() • {• return machine.toString();• }• }

Page 65: Unit 27 Interpreter

65

• public class Variable extends Term • {• protected String name;• protected Term value;• public Variable(String name) • {• this.name = name;• }• public String getName() • {• return name;• }• public void assign(Term term) • {• this.value = term;• }• public boolean equals(Object o) • {• if (o == this)• return true;

• if (!(o instanceof Variable))• return false;

• Variable v = (Variable) o;

• return name.equals(v.name);• }

Page 66: Unit 27 Interpreter

66

• public int hashCode() • {• return name.hashCode();• }• public Machine eval() • {• return value.eval();• }• public String toString() • {• return name + ": " + value;• }• }

Page 67: Unit 27 Interpreter

67

• The book is not yet ready to try and show how to use variables in the implementation of the ForCommand class

• First is shows how some of the simpler commands could be generalized by using references to terms

• In other words, the commands could then be used with either constants or variables which refer to machines rather than machine references themselves

Page 68: Unit 27 Interpreter

68

• The main thing that happens is that whenever a term is used, it is resolved to a machine reference by calling eval() on it

• The CarryCommand class rewritten using terms is shown on the next overhead

Page 69: Unit 27 Interpreter

69

• public class CarryCommand extends Command • {• protected Term from;• protected Term to;

• public CarryCommand(Term fromTerm, Term toTerm) • {• from = fromTerm;• to = toTerm;• }

• public void execute() • {• Robot.singleton.carry(from.eval(), to.eval());• }• }

Page 70: Unit 27 Interpreter

70

• On the next overhead, code for a StartUpCommand class is given which uses terms

• The same approach is used as for the CarryCommand

• Whenever a term is used, it is resolved to a machine reference by calling eval()

Page 71: Unit 27 Interpreter

71

• public class StartUpCommand extends Command • {• protected Term term;

• public StartUpCommand(Term term) • {• this.term = term;• }

• public void execute() • {• Machine m = term.eval();• m.startup();• }• }

Page 72: Unit 27 Interpreter

72

• It’s not very clear what you’ve gained by this since everything has to resolve to a machine

• The explanation, again, stems all the way back to the initial discussion

Page 73: Unit 27 Interpreter

73

• Ultimately, you might have a machine control language, which you parse and then interpret

• The machine control language might use variables

• Including terms, constants, and variables on the interpreter end makes it possible to support variables on the control language end

Page 74: Unit 27 Interpreter

74

• Next, the book tackles the topic of how to write the ForCommand class

• As mentioned already, this is where things get messy

• The book presents partial code• The most twisted part of the implementation

is reserved for a challenge

Page 75: Unit 27 Interpreter

75

• Rather than doing this as a challenge, the complete code is given on the following overheads, broken up with explanations

• The first overhead shows the instance variables and the constructor of the ForCommand class

Page 76: Unit 27 Interpreter

76

• public class ForCommand extends Command • {• protected MachineComponent root;• protected Variable variable;• protected Command body;

• public ForCommand(MachineComponent mc, Variable v, Command body) • {• this.root = mc;• this.variable = v;• this.body = body;• }

Page 77: Unit 27 Interpreter

77

• The constructor, as advertised, takes in a MachineComponent, a Variable, and a Command

• The only particularly notable thing is the naming of the instance variable that has the MachineComponent parameter assigned to it

• It’s called root• Because MachineComponent can be a composite, it

can be a tree of instructions, and the for loop that ForCommand implements will iterate over that tree, using the input parameter as the root node

Page 78: Unit 27 Interpreter

78

• The next overhead shows the implementations of the execute() methods for the ForCommand class

Page 79: Unit 27 Interpreter

79

• public void execute() • {• execute(root);• }

• private void execute(MachineComponent mc) • {• if (mc instanceof Machine) • {• Machine m = (Machine) mc;• variable.assign(new Constant(m));• body.execute();• return;• }

• MachineComposite comp = (MachineComposite) mc;• List children = comp.getComponents();• for (int i = 0; i < children.size(); i++) • {• MachineComponent child = (MachineComponent) children.get(i);• execute(child);• }• }• }

Page 80: Unit 27 Interpreter

80

• The first method on the previous overhead is an execute() command for ForCommand without any input parameters

• Keep in mind that the model that’s being followed is that all necessary values are input at construction time

• Then to execute an instance of ForCommand or any other of the commands, it’s simply necessary to call execute() with no parameters

Page 81: Unit 27 Interpreter

81

• In ForCommand, the execute() command without parameters wraps a call to execute() which takes a single MachineComponent parameter, the root of the tree of machines that is to be iterated over

• This parameter is available because it is passed in at the time the ForCommand object is constructed

Page 82: Unit 27 Interpreter

82

• The second method is the private method, execute(), which takes the reference to the MachineComponent object as its input parameter

• This is the method which the execute() without parameters calls

• This is the method that does the work

Page 83: Unit 27 Interpreter

83

• Once again, the structure of the methods is reminiscent of things that were seen with the composite pattern

• There is a method without parameters that is ultimately implemented by calling a method with a parameter

• The execute() methods are reminiscent of the isTree() methods

• execute() with a parameter is recursive, making it possible to traverse a tree of machines

Page 84: Unit 27 Interpreter

84

• This execute() method breaks into two sub-parts, the non-recursive, base case, and the recursive case

• Consider the recursive part first• It is easier to understand• That part of the code is shown again on the

next overhead so I don’t have to skip back

Page 85: Unit 27 Interpreter

85

• public class ForCommand extends Command • {• protected MachineComponent root;• protected Variable variable;• protected Command body;

• public ForCommand(MachineComponent mc, Variable v, Command body) • {• this.root = mc;• this.variable = v;• this.body = body;• }• …• private void execute(MachineComponent mc) • {• if (mc instanceof Machine) • {• …• }• // Else…• MachineComposite comp = (MachineComposite) mc;• List children = comp.getComponents();• for (int i = 0; i < children.size(); i++) • {• MachineComponent child = (MachineComponent) children.get(i);• execute(child);• }• }

Page 86: Unit 27 Interpreter

86

• If the input parameter is not an individual machine, then it’s a composite

• Cast it to the composite type and acquire a reference to the List (ArrayList) of components that it contains

• Iterate over this list of components

Page 87: Unit 27 Interpreter

87

• What you do with each element is recursively call this same execute() method, passing in each element, in turn, as the explicit parameter

• Do not be confused• In this recursive part of the code you are not

calling execute on individual machines/commands• You are traversing those elements of the tree that

are composite, recursively calling this execute() method on them

Page 88: Unit 27 Interpreter

88

• The first part of the method is where the recursion stops

• This is the part where you encounter tree elements which are leaves, or individual machines

• That part of the code is shown again on the next overhead so I don’t have to skip back

• It will then be discussed, line by line

Page 89: Unit 27 Interpreter

89

• public class ForCommand extends Command • {• protected MachineComponent root;• protected Variable variable;• protected Command body;

• public ForCommand(MachineComponent mc, Variable v, Command body) • {• this.root = mc;• this.variable = v;• this.body = body;• }• … • private void execute(MachineComponent mc) • {• if (mc instanceof Machine) • {• Machine m = (Machine) mc;• variable.assign(new Constant(m));• body.execute();• return;• }• …• }

Page 90: Unit 27 Interpreter

90

• This is precisely the point where things get ugly• It is the point where things depend on breaking

encapsulation• It’s hard to understand what is happening

because you are working with references• It is doubly hard because these are references

that came in at construction time, not parameters that came in as direct input to this method

Page 91: Unit 27 Interpreter

91

• Here are the lines of code, explained step-by-step

• 1.• if (mc instanceof Machine) • You are iterating through a tree of machine

components and you have hit a leaf node, namely a single machine, not a composite

Page 92: Unit 27 Interpreter

92

• 2.• Machine m = (Machine) mc;• You cast the reference from

MachineComponent to Machine• This isn’t too troublesome

Page 93: Unit 27 Interpreter

93

• 3.• variable.assign(new Constant(m));• Inside the call you construct an instance of

Constant using the machine object• This is necessary because you want to use the

assign() method, which takes an instance of Constant as its explicit parameter

• You assign this constant to the reference named variable

Page 94: Unit 27 Interpreter

94

• At this point you need to recall that this Variable reference was passed in when the ForCommand object was being constructed

• It may not be clear what the purpose of this is, but there is nothing apparently wrong (yet)

• There is an instance variable in the ForCommand class that holds the reference to the Variable object

• The key point is this:• Any assignment to the Variable reference here affects the

variable as it was in the client code that constructed the ForCommand object, because the Variable instance variable is a reference that was passed in, and not a simple value

Page 95: Unit 27 Interpreter

95

• 4.• body.execute();• This is the line of code that is the mystery

requiring explanation• You are supposed to be iterating over a collection

of machines• ForCommand has a body• This is the command that is supposed to be

applied to each machine in the collection

Page 96: Unit 27 Interpreter

96

• The question is, in this line of code, where is it apparent that “body” varies according to whatever machine you were on?

• The answer only becomes apparent if you look at an example of a call to construct an instance of ForCommand

• Here is such an example:• Command c = new ForCommand(dublin, v, new ShutDownCommand(v));

Page 97: Unit 27 Interpreter

97

• The first parameter is the collection of machines

• The second parameter is a variable, a placeholder

• The third parameter is an instance of ShutDownCommand, the command that should be applied to each machine as you iterate through the collection

Page 98: Unit 27 Interpreter

98

• The third parameter, an instance of ShutDownCommand, is constructed with a reference to the Variable v as its input parameter

• In other words, the ShutDownCommand that is passed in depends on whatever the value of v is at any given time

Page 99: Unit 27 Interpreter

99

• In the execute() method of ForCommand, every time this line of code is executed

• variable.assign(new Constant(m));• The variable belonging to the

ShutDownCommand is affected

Page 100: Unit 27 Interpreter

100

• This is where encapsulation is being violated• It’s not a violation to pass Variable v in, assign it

to the instance variable named variable, and have variable changed in the execute method

• The violation is that changing variable in the execute() method changes the value inside the ShutDownCommand object

• This happens without calling a set method on the ShutDownCommand object

Page 101: Unit 27 Interpreter

101

• This is what makes the code so devilishly hard to follow

• You make a change to variable in the execute() method and there is nothing in there that tells you that the ShutDownCommand is going to be affected

• You only know that by looking at the calling client code where you pass v and a ShutDownCommand that was constructed using v

Page 102: Unit 27 Interpreter

102

• Look once more at the code on the following overhead

• To the good: Yes, the book accomplishes its goal

• You can iterate over a collection of machines• When you do so, you can call body.execute()

which will execute the desired command on each machine encountered

Page 103: Unit 27 Interpreter

103

• public class ForCommand extends Command • {• protected MachineComponent root;• protected Variable variable;• protected Command body;

• public ForCommand(MachineComponent mc, Variable v, Command body) • {• this.root = mc;• this.variable = v;• this.body = body;• }• … • private void execute(MachineComponent mc) • {• if (mc instanceof Machine) • {• Machine m = (Machine) mc;• variable.assign(new Constant(m));• body.execute();• return;• }• …• }

Page 104: Unit 27 Interpreter

104

• Note that this execute call is not a recursive call of the execute inside the ForCommand class

• It is a call to execute on whatever command was passed into the ForCommand class when it was constructed

• If you want to toy with insanity, think of how you would do nested loops using this machinery

• You would pass a ForCommand object as the body to another ForCommand object…

Page 105: Unit 27 Interpreter

105

• This code is not easy to understand, especially without seeing how it’s called

• The lack of understandability is unfortunate• It is also a symptom of the fact that as

implemented by the authors, this design pattern relies on violating encapsulation

Page 106: Unit 27 Interpreter

106

• The book next gives a complete little program that shows how you could use ForCommand to shut down every machine in a factory

• The idea is that you would use ForCommand to iterate over all of the machines in the factory, where the body of the loop consisted of a call to a ShutDownCommand command with the current machine as its parameter

• The code is given on the next overhead

Page 107: Unit 27 Interpreter

107

• public class ShowDown • {• public static void main(String[] args) • {• MachineComposite dublin = OozinozFactory.dublin();• Variable v = new Variable("machine");• Command c = new ForCommand(dublin, v, new ShutDownCommand(v));• c.execute();• }• }

Page 108: Unit 27 Interpreter

108

• The previous example is mainly just a reminder of the power of iteration

• However, it also serves the purpose of beginning to illustrate the power of the Interpreter design pattern

• Instead of having to hand code the shutdown of every machine, it is possible to do this by constructing and executing a single instance of the ForCommand class

Page 109: Unit 27 Interpreter

109

• Continuing with the development of the Interpreter design pattern:

• An interpreter would become even more complete by adding commands like IfCommand and WhileCommand which are additional constructs of high level languages

• Both of these constructs require the ability to test a condition that will give a boolean result

Page 110: Unit 27 Interpreter

110

• The book hints that the way to do this might be to develop a new hierarchy of boolean classes

• However, the authors opt to put the new classes into the Term hierarchy they already introduced

• It’s hard to say whether this is a great idea

Page 111: Unit 27 Interpreter

111

• It has the obvious advantage of not requiring that a new hierarchy be developed

• It also has the apparent disadvantage that the classes in the hierarchy don’t necessarily seem related

• However, it does work because the new classes will be based on an eval() method, and that’s the method that Variable and Constant classes were based on

Page 112: Unit 27 Interpreter

112

• boolean results will be modeled using this technique:• The eval() method will be typed to return a reference

to a machine• If eval() returns null, this will signify false• If eval() returns a reference to an actual machine, that

will signify true• The UML diagram on the next overhead shows the

new Term hierarchy with an Equals and a HasMaterial class added to it

Page 113: Unit 27 Interpreter

113

Page 114: Unit 27 Interpreter

114

• The Equals class has a constructor that takes in two terms as parameters

• The eval() method doesn’t take in any parameters• It uses the eval() method of the Term class to convert its

instance variable terms to machine references• It then uses the equals() method of the Machine class to

test for equality• It returns the reference to the first machine if the two

machines are equal, and returns null if they’re not equal• The code is shown on the following overhead

Page 115: Unit 27 Interpreter

115

• public class Equals extends Term • {• protected Term term1;• protected Term term2;

• public Equals(Term term1, Term term2) • {• this.term1 = term1;• this.term2 = term2;• }

• public Machine eval() • {• Machine m1 = term1.eval();• Machine m2 = term2.eval();• return m1.equals(m2) ? m1 : null;• }• }

Page 116: Unit 27 Interpreter

116

• The HasMaterial class has a constructor that takes in one term as a parameter

• The eval() method doesn’t take in any parameters• It uses the eval() method of the Term class to convert its

instance variable term to a machine reference• It then uses the hasMaterial() method of the Machine

class to see whether the machine has any material• It returns the reference to the machine if it has material,

and returns null if it doesn’t• The code is shown on the following overhead

Page 117: Unit 27 Interpreter

117

• public class HasMaterial extends Term • {• protected Term term;

• public HasMaterial(Term term) • {• this.term = term;• }

• public Machine eval() • {• Machine m = term.eval();• return m.hasMaterial() ? m : null;• }• }

Page 118: Unit 27 Interpreter

118

• If you’re going to have if statements, it is helpful to also have a null command

• This represents the situation where you have either an empty if or an empty else

• In practice, this is just a command where the execute() method itself is empty

• Code for a NullCommand class is shown on the next overhead

Page 119: Unit 27 Interpreter

119

• public class NullCommand extends Command• {• public void execute()• {• }• }

Page 120: Unit 27 Interpreter

120

• With boolean conditions modeled, it’s possible to add an IfCommand and a WhileCommand to the Command hierarchy

• The UML diagram on the next overhead shows this• Note that just like with ForCommand, IfCommand

and WhileCommand have a reference to another command

• This other command will be the body of the if statement or the while statement, respectively

Page 121: Unit 27 Interpreter

121

Page 122: Unit 27 Interpreter

122

• The book does the completion of the code for the IfCommand, and the entirety of the code for the WhileCommand as challenges

• As usual, it’s easiest not to bother with incomplete code and to go directly to the challenges and their solutions

Page 123: Unit 27 Interpreter

123

• Challenge 25.2• Complete the code in the execute() method of

the IfCommand class.• Solution 25.2• One solution is:• [See the complete code on the following

overhead.]

Page 124: Unit 27 Interpreter

124

• public class IfCommand extends Command • {• protected Term term;• protected Command body;• protected Command elseBody;

• public IfCommand(Term term, Command body, Command elseBody) • {• this.term = term;• this.body = body;• this.elseBody = elseBody;• }

• public void execute() • {• if (term.eval() != null)• body.execute();• else• elseBody.execute();• }• }

Page 125: Unit 27 Interpreter

125

• Challenge 25.3• Write the code for the WhileCommand class.• Solution 25.3• One way to write WhileCommand.java is:• [See the code on the following overhead.]

Page 126: Unit 27 Interpreter

126

• public class WhileCommand extends Command • {• protected Term term;• protected Command body;

• public WhileCommand(Term term, Command body) • {• this.term = term;• this.body = body; • }

• public void execute() • {• while (term.eval() != null)• body.execute();• }• }

Page 127: Unit 27 Interpreter

127

• Once you start getting used to the Interpreter design pattern, the code for these command classes doesn’t seem too difficult

• The execute() method “wraps” the logic for if and while, using terms and bodies as stand-ins for whatever actual items and actions come from the problem domain

• In particular, these two kinds of commands are easier than the ForCommand, because no variable is involved

Page 128: Unit 27 Interpreter

128

• The book next illustrates using the WhileCommand

• The code for the ShowWhile program is given on the following overhead

• While the start press has material, that material will be carried to the fuser

Page 129: Unit 27 Interpreter

129

• public class ShowWhile • {• public static void main(String[] args) • {• MachineComposite dublin = OozinozFactory.dublin();• Term starPress = new Constant((Machine)

dublin.find("StarPress:1401"));• Term fuser = new Constant((Machine) dublin.find("Fuser:1101"));• • starPress.eval().load(new Bin(77));• starPress.eval().load(new Bin(88));• • WhileCommand command = new WhileCommand(• new HasMaterial(starPress),• new CarryCommand(starPress, fuser));• command.execute();• }• }

Page 130: Unit 27 Interpreter

130

• As with the other programs that illustrated the use of the Interpreter design pattern, this one ended with the construction of a single command object and the calling of execute() on that object

• That one object had packaged up in it potentially many other individual commands

Page 131: Unit 27 Interpreter

131

• The book explains what’s happening with this one sentence, which summarizes the design pattern:

• “The command object is an interpreter that interprets execute() to mean unload all the bins from star press 1401.”

• In other words, the process of interpreting is simply polymorphism in action

Page 132: Unit 27 Interpreter

132

• You have a hierarchy of command classes• Each class implements an execute() method• You can compose complex commands based both

on the composite design pattern and inherently complex commands like for, if, and while

• Then at run time, interpretation simply means letting polymorphism figure out what execute() means for each of the individual commands that are encountered

Page 133: Unit 27 Interpreter

133

• Once again, this pattern starts to look like lots of other patterns that functioned as a result of polymorphism

• At this point, the book’s devotion to the concept of intent starts to seem more reasonable

• Even though this pattern is a “simple” application of polymorphism, what is being accomplished is not obviously so simple

Page 134: Unit 27 Interpreter

134

• This was the book’s definition of the pattern:• “The intent of the Interpreter pattern is to let

you compose executable objects according to a set of composition rules that you define.”

• Once you’ve seen the pattern, maybe the definition makes sense

Page 135: Unit 27 Interpreter

135

• A clumsier, more functionally oriented description might go something like this:

• The Interpreter design pattern is based on classes that wrap the concepts of a programming language

• The classes have a common execute() method, so the pattern depends on polymorphism in order to work

Page 136: Unit 27 Interpreter

136

• Challenge 25.4• Close this book and write down a short

explanation of the difference between Command and Interpreter.

• Comment mode on:• Sure, now they get all strict and make us close

the book…

Page 137: Unit 27 Interpreter

137

• Solution 25.4• One answer is: The intent of the Interpreter

pattern is to let you compose executable objects from a hierarchy of classes that provide various interpretations of a common operation. The intent of Command is merely to encapsulate a request in an object

Page 138: Unit 27 Interpreter

138

• Solution 25.4, cont’d.• Can an interpreter object function as a

command? Sure! The question of which pattern applies depends on your intent. Are you creating a toolkit for composing executable objects, or are you encapsulating a request in an object?

Page 139: Unit 27 Interpreter

139

• Comment mode on:• I would summarize my own answer in this way:• If you are trying to build up a hierarchy of

command classes that wrap a set of programming language constructs, then you’re using the Interpeter design pattern

• If you are trying to wrap a single command for one-shot use, then you’re using the Command pattern

Page 140: Unit 27 Interpreter

140

• At this point the book turns to the topic which I mentioned at the beginning

• Writing programs to create interpreter command objects seems kind of silly

• Why not just write the code for machine and robot control programs?

• The book’s scenario is as follows

Page 141: Unit 27 Interpreter

141

• You could write a simple high-level language that was designed for machine and robot control

• The book gives this as a pseudo-code example of a program in that language:

• for(m in factory)• if(not(m is unloadBuffer))• ub = findUnload for m• while(m hasMaterial)• carry(m, ub)

Page 142: Unit 27 Interpreter

142

• Then, in theory, you could write a parser program that took machine control programs as input and created interpreters as output

• In other words, you wouldn’t have to handcode a program like ShowInterpreter; the parser would do it for you

Page 143: Unit 27 Interpreter

143

• The benefit you would gain is that users would not have to code in Java

• They could code in the machine control language and the parser/interpreter combination would produce Java programs that implemented the machine control programs written by users

Page 144: Unit 27 Interpreter

144

Summary

• The Interpreter design pattern is based on a hierarchy of command classes

• The names of the command classes suggest what it is they do

• Each class implements an execute() method• The implementation should correspond to the

name of the class

Page 145: Unit 27 Interpreter

145

• The class constructors should take the needed input parameters

• The execute method should then work on instance variables and not need input parameters

• Some of the commands will be simple actions• Others will be commands that make it possible

to compose multiple simple commands

Page 146: Unit 27 Interpreter

146

• The interpreter design pattern may be accompanied by a hierarchy that defines terms for variables, booleans, etc.

• In order to be practical, interpreters may also be used along with parsers, although how parsing works wasn’t really covered in the chapter

Page 147: Unit 27 Interpreter

147

The End