Compiler Design Spring 2018 4.X Patterns (again) Thomas R. Gross - - PowerPoint PPT Presentation

compiler design
SMART_READER_LITE
LIVE PREVIEW

Compiler Design Spring 2018 4.X Patterns (again) Thomas R. Gross - - PowerPoint PPT Presentation

Compiler Design Spring 2018 4.X Patterns (again) Thomas R. Gross Computer Science Department ETH Zurich, Switzerland 1 Why? Remember questionnaire (from the beginning of the semester)? Question 7: Please name three design patterns


slide-1
SLIDE 1

Compiler Design

Spring 2018

4.X Patterns (again)

1

Thomas R. Gross Computer Science Department ETH Zurich, Switzerland

slide-2
SLIDE 2

Why?

§ Remember questionnaire (from the beginning of the semester)? § Question 7: “Please name three design patterns that you encountered in earlier projects/classes.” § Answers

§ Complete (3+ patterns): 33% § Blank: 55%

2

slide-3
SLIDE 3

Patterns

§ Singleton: 27% § Factory: 27% § Visitor: 22% Not a pattern:

§ Object-oriented programming § Design by contract § Functional programming § Lazy loading § Inheritance

3

slide-4
SLIDE 4

Patterns – some technical reasons

§ Control flow always difficult to deal with § Patterns like Strategy or Iterator raise the level of programming

§ Hide details § Easier to read than explicit control flow statements § Simpler to write § Easier to extend/understand/maintain

4

slide-5
SLIDE 5

Trivial example

§ Print date using different formats § Option 1: Test at each place in the program P where the date is to be printed

switch(format): { case (INTERNATIONAL): // print YEAR-MONTH-DAY break; case (BANK): // print MONTH-DAY-YEAR break; ... }

§ Option 2: Invoke function/method F passed to P

§ F is defined so that the correct format is chosen

5

slide-6
SLIDE 6

Auxiliary classes

import java.util.Calendar; import java.util.GregorianCalendar; import java.util.Date; class MyDate { // Won’t work in long-lived programs int day; int month; int year; MyDate() { Calendar cal = new GregorianCalendar(); year = cal.get(cal.YEAR); month = cal.get(cal.MONTH); day = cal.get(cal.DAY_OF_MONTH); } }

6

slide-7
SLIDE 7

Select format 1 (international)

interface Print { void print(); } class InternationalFormatPrint implements Print { MyDate d_; InternationalFormatPrint(MyDate d) { d_ = d; } public void print() { System.out.println(d_.day + "/" + d_.month + "/" + d_.year ); } }

7

slide-8
SLIDE 8

Select format 2 (bank)

class BankFormatPrint implements Print { MyDate d_; BankFormatPrint (MyDate d) { d_ = d; } public void print() { System.out.println(d_.month + "/" + d_.day +"/" + d_.year ); } }

8

slide-9
SLIDE 9

Example

public static void main(String args[]) { MyDate d = new MyDate(); Print p = selectPrinter(d); doThePrinting(p); } static Print selectPrinter(Date d) { if (user.input() == ‘b‘) { return new BankFormatPrint(d); } else { return new InternationalFormatPrint(d); } } static void doThePrinting(Print service) { service.print(); }

9

slide-10
SLIDE 10

Output

Test6> java Test6 30/1/2018 Test6> java Test6 1/30/2018 § Not a big deal

§ (This is a simple example after all)

§ But the idea is powerful

§ No need to deal with a possibly complicated switch-statement § Only passing the printer instance as parameter is needed

10

slide-11
SLIDE 11

Other advantage: Extensibility

§ Imagine adding support for a new format, e.g., Japanese § With Option 1: Extending switch statement is required

switch(format): { case (INTERNATIONAL): // print YEAR-MONTH-DAY break; case (BANK): // print MONTH-DAY-YEAR break; case (JAPANESE): // print YEAR-MONTH-DAY break; }

11

slide-12
SLIDE 12

Other advantage: Extensibility

§ At all places where formatting is needed

§ Error-prone § High risk of introducing inconsistent behavior

12

slide-13
SLIDE 13

Other advantage: Extensibility

§ Option 2: Requires only adding a new implementation for the Print interface

class JapaneseFormatPrint implements Print { MyDate d_; JapaneseFormatPrint(MyDate d) { d_ = d; } public void print() { System.out.println(d_.year + "/" + d_.month +"/" + d_.day ); } }

§ Where new formatting is needed: Pass a JapaneseFormatPrint instance to existing code

13

slide-14
SLIDE 14

public static void main(String args[]) { MyDate d = new MyDate(); Print p = selectPrinter(d); doThePrinting(p); } static Print selectPrinter(Date d) { if (user.input() == ‘b‘) { return new BankFormatPrint(d); } else if (user.input() == ‘j‘){ return new JapaneseFormatPrint(d); } else { return new InternationalFormatPrint(d); } } static void doThePrinting(Print service) { service.print(); }

14

slide-15
SLIDE 15

The Strategy pattern

§ You’ve just seen an example of the Strategy pattern

15

Context contextInterface() Strategy algorithmInterface() ConcreteStrategy3 algorithmInterface() ConcreteStrategy2 algorithmInterface() ConcreteStrategy1 algorithmInterface()

slide-16
SLIDE 16

The Strategy pattern

§ You’ve just seen an example of the Strategy pattern

16

MyDate

// direct access to fields

Print print() JapaneseFormatPrint print() Int’lFormatPrint print() BankFormatPrint print()

slide-17
SLIDE 17

The Strategy pattern

§ Idea: Encapsulate a set of related algorithms into a class hierarchy

§ Benefit: Simplify control-flow (e.g., reduce the need for conditional statements) § Benefit: Algorithm can be changed independently of context § Benefit: Decouple implementation of algorithm from data structure(s) in context

17

slide-18
SLIDE 18

Is Strategy really that great?

§ Should we always use Strategy when our program uses at least two different algorithms on one data structure?

§ It depends

§ A pattern is a solution that works well in some settings

§ But not always § You have to weight pros/cons

18

slide-19
SLIDE 19

Pros/cons

§ A switch-statement is not that bad after all…

§ If you have a program with two algorithms and a data structure § A program will not be changed/extended § Don’t forget: Change is rather the norm and not an exception

§ Implementing Strategy (often) requires interface/virtual calls

§ (Some) VM engineers: Don’t use virtual calls, they’re expensive § Good for performance, maintenance cost paid later

19

slide-20
SLIDE 20

An alternative

§ Advantage: Simpler class structure § Disadvantage: Mixes MyDate and algorithms that operate on it § Can become a problem if algorithms and/or data structure in MyDate complicated

20

MyDate print() JapaneseFormatDate print() Int’lFormatDate print() BankFormatDate print()

slide-21
SLIDE 21

Working with data structures

§ MyDate: Only three integer fields

§ Direct access to fields sufficient to print date

21

MyDate

// direct access to fields

Print print() JapaneseFormatPrint print() Int’lFormatPrint print() BankFormatPrint print()

slide-22
SLIDE 22

Working with complex data structures

§ What should we do if the data structure is complex?

§ We could use an iterator to enumerate all elements

22

slide-23
SLIDE 23

Working with complex data structures

§ Example: list of dates

class JapaneseFormatPrint implements Print { List<MyDate> list_; JapaneseFormatPrint(List<MyDate> list) { list_ = list; } public void print() { Iterator iter; while (iter.hasNext()) { MyDate d = iter.next() System.out.println(d_.year + "/" + d_.month +"/" + d_.day ); } } }

23

slide-24
SLIDE 24

What about accessing even more complex data structures?

§ There may not be an iterator § The order of processing/invoking a method may matter

§ (Just think of trees)

§ Visitor pattern internalizes the logic of “visiting” the elements

24

slide-25
SLIDE 25

Visitor

§ Coupling of data structure and access method(s) § Powerful in connection with trees § Object must be prepared to “accept” a visitor § Example: arithmetic expressions

§ Sums § Constants

25

slide-26
SLIDE 26

Visitor

// Data structure abstract class ArithExpr { abstract int accept(Visitor v); } // Visitor interface Visitor { int forConst(Const c); int forSum(Sum s); }

26

slide-27
SLIDE 27

class Const extends ArithExpr { private int value; Const (int v) { value = v; } int getValue() { return value; } int accept(Visitor v) { return v.forConst(this); } }

27

slide-28
SLIDE 28

class Sum extends ArithExpr { ArithExpr left, right; Sum (ArithExpr l, ArithExpr r) { left = l; right = r; } ArithExpr getLeft() { return left;} ArithExpr getRight() { return right;} int accept(Visitor v) { return v.forSum(this); } }

28

slide-29
SLIDE 29

Visitor examples

class EvalVisitor implements Visitor { public int forConst(Const c) { return c.getValue(); } public int forSum(Sum s) { return s.getLeft().accept(this) + s.getRight().accept(this); } } class CountVisitor implements Visitor { public int forConst(Const c) { return 1;} public int forSum(Sum s) { return s.getLeft().accept(this) + s.getRight()).accept(this); } }

slide-30
SLIDE 30

Example, continued

class ShowArithVisitors { public static void main(String[] args) { ArithExpr c2, c3, s1, s2; c2 = new Const(2); c3 = new Const(3); s1 = new Sum(c2,c3); s2 = new Sum(c2, s1); Visitor v1 = new EvalVisitor(); Visitor v2 = new CountVisitor(); System.out.println(s2.accept(v1)); System.out.println(s2.accept(v2)); }

slide-31
SLIDE 31

ObjectStructure ConcreteVisitor visitConcreteElem(ce: ConcreteElement) Visitor {interface} visitConcreteElem(ce: Element) ConcreteElement accept(v: Visitor) Element {interface} accept(v: Visitor)

accept(v: Visitor) { v.visitConcreteElem(this) }

slide-32
SLIDE 32

Discussion

§ Who’s responsible for traversing the object structure? § In our case: the visitor

class EvalVisitor implements Visitor { … public int forSum(Sum s) { return s.getLeft().accept(this) + s.getRight().accept(this); } }

§ Could be the object structure as well

class Sum extends ArithExpr { … int accept(Visitor v) { return getLeft().accept(v) + getRight().accept(v); } }

32

slide-33
SLIDE 33

Discussion (cont’d)

§ Should we always use the Visitor pattern for programs

  • perating on tree-like object structures?

§ It depends.

§ Visitor beneficial if:

§ Object structure contains objects with different (unrelated) functionality

§ E.g., Const represents a value via the field value Sum is an arithmetic expression with fields left and right

33

slide-34
SLIDE 34

class Const extends ArithExpr { private int value; Const (int v) { value = v; } int getValue() { return value; } int accept(Visitor v) { return v.forConst(this); } }

34

slide-35
SLIDE 35

class Sum extends ArithExpr { ArithExpr left, right; Sum (ArithExpr l, ArithExpr r) { left = l; right = r; } ArithExpr getLeft() { return left;} ArithExpr getRight() { return right;} int accept(Visitor v) { return v.forSum(this); } }

35

slide-36
SLIDE 36

Discussion (cont’d)

§ Should we always use the Visitor pattern for programs

  • perating on tree-like object structures?

§ It depends.

§ Visitor beneficial if:

§ Object structure contains objects with different (unrelated) functionality

§ E.g., Const represents a value via the field value Sum is an arithmetic expression with fields left and right

§ Object structure changes rarely but new operations are added often

§ E.g., JavaLi compiler: IR changes rarely, various operations implemented in visitors

36

slide-37
SLIDE 37

Summary

§ Design pattern: A possible way to design (part of) your program

§ (Some) benefits: Simpler code, extensibility, maintainability § Not a general solution: You have to weigh pros/cons

§ Patterns we’ve talked about: Strategy, Iterator (briefly), Visitor § More to come…

37

slide-38
SLIDE 38

Observer

§ Original problem: need to show an object i and want to update each view upon a change § Example: table with values

§ Text § Bar graph § Pie chart

§ If there is a change: Need to redraw the figures

§ Allow changes only to text... § Modify text in response to changes to the figures

slide-39
SLIDE 39

Multiple views

20 40 60 80 100 1st Qtr 2nd Qtr 3rd Qtr 4th Qtr North West East 1s 1st Qt Qtr 2n 2nd Qt Qtr 3r 3rd Qt Qtr 4t 4th Qt Qtr Ea East 2 0 . 2 0 . 4 2 7 . 2 7 . 4 9 0 9 0 2 0 . 2 0 . 4 Wes West 3 0 . 3 0 . 6 3 8 . 3 8 . 6 3 4 . 3 4 . 6 3 1 . 3 1 . 6 No North rth 4 5 . 4 5 . 9 4 6 . 4 6 . 9 4 5 4 5 4 3 . 4 3 . 9 10 20 30 40 50 60 70 80 90 100 1st Qtr 2nd Qtr 3rd Qtr 4th Qtr East West North

slide-40
SLIDE 40

Basic idea

§ The table object (base object) is connected with the presentation objects (text, bar chart, pie chart, etc.)

§ All these objects are independent

§ Each presentation object is notified when there is a change to the base object § Changes result in events

§ Notification: send a message § Sending a message: invoking a method

slide-41
SLIDE 41

Observer

§ Base object: subject § Presentation object: observer

§ Informed about updates by subject

§ Observers register with the subject that they want to be informed

§ A method “update” performs any necessary steps § Must allow way to de-register

slide-42
SLIDE 42

Observer

Subject Observer attach(Observer) detach(Observer) notify() update() for all obj in

  • bservers

{

  • bj.update()

} ConcreteSubject getState() setState() ConcreteObserver update()

  • bserverState =

subject.getState( )

*

  • bserver

s

  • bserverState

subject return subjectState

slide-43
SLIDE 43

Observer in action

Concrete Subject Concrete Observer 1 Concrete Observer 2

setState() notify() update() getState() update() getState()

slide-44
SLIDE 44

Another example: Working with collections

§ Iterator delivers objects (references to objects) § Methods (defined in class for instances) define operations

  • n instance

§ You want to allow extension

§ Introduce sub-class, override method § Provide hook for externally defined functions

§ Apply a function to all elements of a set/collection/...

47

slide-45
SLIDE 45

Practice

§ Apply a function F to all elements of a set/collection/...

§ Provide hook for externally defined functions

§ Example of “high order functions”

§ Function F is the “variable”

48

slide-46
SLIDE 46

Practice

§ Given: some class C for objects we want to work with

§ Nodes in a tree, records of persons, ....

§ A hook (map) in class C that allows us to call methods

§ Including the function F § Hook must allow parameters

§ An interface I that prescribes how method is to be invoked

§ Interface must contain a method (call it “mapIt”)

§ For Java we need to put the definition of function F into a class (I_F)

§ Implementation of mapIt

§ No need to extend C, must only implement an interface

49

slide-47
SLIDE 47

Example

§ Nodes in a list

§ Class C: DList (double-linked list of nodes) § DList declares “map“

50

slide-48
SLIDE 48

List

class Node { private Object value_; private Node next_; private Node prev_; Node(Object obj) { value_ = obj; prev_ = null; next_ = null; } void setValue (Object obj) { value_ = obj;} Object getValue () { return value_;} void setNext (Node next) { next_ = next; } void setPrev (Node prev) { prev_ = prev;} Node getNext () { return next_; } Node getPrev () { return prev_; } }

51

slide-49
SLIDE 49

Class C: DList

// Double-linked list class DList { private Node head_; private Node tail_; DList() { head_ = null; tail_ = null; } void map(FunctionHandle f) { Iterator i_ = createFwdIterator(); for (i_.first(); !i_.isDone(); i_.next()) { Node node_ = (Node) i_.getCurrent(); f.mapIt(node_); } } // map // ... }

52

slide-50
SLIDE 50

Example

§ Nodes in a list

§ Class C: DList (double-linked list of nodes) § DList declares “map“

§ Interface I: FunctionHandle

§ Declares “mapIt”

54

slide-51
SLIDE 51

Interface I and class I_F

interface FunctionHandle { void mapIt(Node node); }

// Print elements class Function1 implements FunctionHandle { public void mapIt(Node node) { System.out.println(node.getValue()); } } // Increment (Integer) elements class Function2 implements FunctionHandle { public void mapIt(Node node) { node.setValue(new Integer( (((Integer) node.getValue()).intValue()) + 1) ); } }

55

slide-52
SLIDE 52

Example

§ Nodes in a list

§ Class C: DList (double-linked list of nodes) § DList declares “map“

§ Interface I: FunctionHandle

§ Declares “mapIt”

§ Classes I_F define functions you want invoke: Function1 and Function2

§ Function1: print node value § Function2: increment node value

56

slide-53
SLIDE 53

Interface I and class I_F

interface FunctionHandle { void mapIt(Node node); }

// Print elements class Function1 implements FunctionHandle { public void mapIt(Node node) { System.out.println(node.getValue()); } } // Increment (Integer) elements class Function2 implements FunctionHandle { public void mapIt(Node node) { node.setValue(new Integer( (((Integer) node.getValue()).intValue()) + 1) ); } }

57

slide-54
SLIDE 54

Use

public class Map2Example { public static void main(String args[]) { DList list = new DList(); // Initialize list Iterator iter = list.createFwdIterator(); FunctionHandle fct1 = new Function1(); FunctionHandle fct2 = new Function2(); list.map(fct1); list.map(fct2); } }

§ Compact § Control flow is hidden

58