Design patterns (part 3)

Similar documents
CSE 331 Software Design & Implementation

Design patterns (part 2) CSE 331 Spring 2010

CSE 331 Software Design & Implementation

CSE 331 Software Design & Implementation

CSE 331 Software Design & Implementation

Design patterns (part 2)

Design Patterns Maria Zontak

Outline. Design Patterns, cont. Wrappers. Adapter Pattern. Based on material by Michael Ernst, University of Washington

CSE 401/M501 Compilers

CSE 431S Type Checking. Washington University Spring 2013

CSE P 501 Compilers. Implementing ASTs (in Java) Hal Perkins Autumn /20/ Hal Perkins & UW CSE H-1

Design Patterns. Visitor Pattern. Hans Vangheluwe and Alexandre Denault

CSE P 501 Compilers. Implementing ASTs (in Java) Hal Perkins Winter /22/ Hal Perkins & UW CSE H-1

CS 4120 Introduction to Compilers

Compilers CS S-07 Building Abstract Assembly

Prof. Mohamed Hamada Software Engineering Lab. The University of Aizu Japan

CPS2000 Compiler Theory & Practice

An Automatic Visitor Generator for Ada

Visitor Pattern CS356 Object-Oriented Design and Programming November 5, 2014 Yu Sun, Ph.D.

Lecture 8 CS 412/413 Spring '00 -- Andrew Myers 2. Lecture 8 CS 412/413 Spring '00 -- Andrew Myers 4

CSE 12 Abstract Syntax Trees

6.170 Lecture 15 Design Patterns

Semantic analysis. Compiler Construction. An expression evaluator. Examples of computations. Computations on ASTs Aspect oriented programming

CS412/CS413. Introduction to Compilers Tim Teitelbaum. Lecture 17: Types and Type-Checking 25 Feb 08

A Simple Syntax-Directed Translator

CS558 Programming Languages

Semantic Analysis. Compiler Architecture

Visitors. Move functionality

.jj file with actions

Tecniche di Progettazione: Design Patterns

Introduction to Visual Basic and Visual C++ Introduction to Java. JDK Editions. Overview. Lesson 13. Overview

Intermediate Code Generation

Semantic Analysis. How to Ensure Type-Safety. What Are Types? Static vs. Dynamic Typing. Type Checking. Last time: CS412/CS413

Chapter 4. Abstract Syntax

MATVEC: MATRIX-VECTOR COMPUTATION LANGUAGE REFERENCE MANUAL. John C. Murphy jcm2105 Programming Languages and Translators Professor Stephen Edwards

The Compiler So Far. CSC 4181 Compiler Construction. Semantic Analysis. Beyond Syntax. Goals of a Semantic Analyzer.

CS2110 Assignment 3 Inheritance and Trees, Summer 2008

Program Representations

Haskell s Take on the Expression Problem

BFH/HTA Biel/DUE/Course 355/ Software Engineering 2

Chapter 8, Design Patterns Visitor

SEMANTIC ANALYSIS TYPES AND DECLARATIONS

The Lorax Programming Language

Semantic Processing. Semantic Errors. Semantics - Part 1. Semantics - Part 1

Object-Oriented Oriented Programming

Parsing Techniques. AST Review. AST Data Structures. LL AST Construction. AST Construction CS412/CS413. Introduction to Compilers Tim Teitelbaum

2.2 Syntax Definition

Object oriented programming. Instructor: Masoud Asghari Web page: Ch: 3

Compilers Project 3: Semantic Analyzer

COMP-421 Compiler Design. Presented by Dr Ioanna Dionysiou

Writing Evaluators MIF08. Laure Gonnord

Chapter Contents. Trees. Tree Concepts. Hierarchical Organization. Hierarchical Organization. Hierarchical Organization.

Chapter 2 A Quick Tour

Lecture 7: Type Systems and Symbol Tables. CS 540 George Mason University

A programming language requires two major definitions A simple one pass compiler

Lecture 16 & 17. Crosscutting Concerns N-dimensional separation of concerns, AspectJ, Mixin, Concern Graph, etc.

Faculty of Electrical Engineering, Mathematics, and Computer Science Delft University of Technology

Visitor Pattern.» Represent an operation to be performed on all of the components of an object structure

More On Syntax Directed Translation

Today. Assignments. Lecture Notes CPSC 326 (Spring 2019) Operator Associativity & Precedence. AST Navigation. HW4 out (due next Thurs)

Polyglot Tutorial PLDI 2014

Higher-Order Intensional Type Analysis. Stephanie Weirich Cornell University

Mid-Term 2 Grades

IC Language Specification

CS1622. Semantic Analysis. The Compiler So Far. Lecture 15 Semantic Analysis. How to build symbol tables How to use them to find

Introduction to Programming Using Java (98-388)

Syntax and Grammars 1 / 21

CS558 Programming Languages

Abstract Syntax Trees

Weiss Chapter 1 terminology (parenthesized numbers are page numbers)

Implementing Actions

Short Notes of CS201

CSE 504. Expression evaluation. Expression Evaluation, Runtime Environments. One possible semantics: Problem:

drawobject Circle draw

LECTURE 16. Functional Programming

CS201 - Introduction to Programming Glossary By

OOPLs - call graph construction Compile-time analysis of reference variables and fields. Example

Design Patterns (1) CSE 331 University of Washington

CSc 553. Principles of Compilation. 16 : OO Languages Polymorphism. Department of Computer Science University of Arizona

(Not Quite) Minijava

Prof. Mohamed Hamada Software Engineering Lab. The University of Aizu Japan

Think of drawing/diagramming editors. ECE450 Software Engineering II. The problem. The Composite pattern

GO MOCK TEST GO MOCK TEST I

Semantic Analysis. CSE 307 Principles of Programming Languages Stony Brook University

Building Compilers with Phoenix

Compilers CS S-05 Semantic Analysis

Semantic actions for expressions

Chapter 4 Trees. Theorem A graph G has a spanning tree if and only if G is connected.

Object-Oriented Languages and Object-Oriented Design. Ghezzi&Jazayeri: OO Languages 1

Compiling Techniques

Pattern Examples Behavioural

Outline. Java Models for variables Types and type checking, type safety Interpretation vs. compilation. Reasoning about code. CSCI 2600 Spring

5. Syntax-Directed Definitions & Type Analysis

Introduction to Python and Programming. 1. Python is Like a Calculator. You Type Expressions. Python Computes Their Values /2 2**3 3*4+5*6

J&: Nested Intersection for Scalable Software Composition

Inheritance, Polymorphism and the Object Memory Model

Pace University. Fundamental Concepts of CS121 1

Chapter 13 Object Oriented Programming. Copyright 2006 The McGraw-Hill Companies, Inc.

Formal Semantics of Programming Languages

Winter Compiler Construction Who. Mailing list and forum

Transcription:

Design patterns (part 3) CSE 331 University of Washington Michael Ernst

Outline Introduction to design patterns Creational patterns (constructing objects) Structural patterns (controlling heap layout) Behavioral patterns (affecting object semantics)

Review: Composite pattern Composite permits a client to manipulate either an atomic unit or a collection of units in the same way Good for dealing with part-whole relationships Example behavior: traversing composites Goal: perform operations on all parts of a composite Idea: generalize the notion of an iterator

Composite example 1: Bicycle Bicycle Frame Drivetrain Wheel Tire Tube Tape Rim Nipples Spokes Hub Skewer Lever Body Cam Rod Acorn nut...

Methods on components abstract class BicycleComponent { int weight(); float cost(); class Wheel extends BicycleComponent { float assemblycost; Skewer skewer; Hub hub;... float cost() { return assemblycost + skewer.cost() + hub.cost() +...; class Bicycle extends BicycleComponent { float assemblycost; Frame frame; Drivetrain drivetrain; Wheel frontwheel;... float cost() { return assemblycost + frame.cost() + drivetrain.cost() + frontwheel.cost() +...;

Composite example 2: Libraries Library Section (for a given genre) Shelf Volume Page Column Word Letter interface Text { String gettext(); class Page implements Text { String gettext() {... return the concatenation of the column texts...

Composite example 3: Representing Java code x = foo * 10 + c / d; = AST = Abstract Syntax Tree x + * / foo 10 c d

Abstract syntax tree (AST) for Java code class PlusOp extends Expression { // + operation Expression leftexp; Expression rightexp; class VarRef extends Expression { // variable reference String varname; class EqualOp extends Expression { // equality test a==b Expression lvalue; // left-hand side: "a" in "a==b" Expression rvalue; // right-hand side: "b" in "a==b" class CondExpr extends Expression { // a?b:c Expression condition; Expression thenexpr; // value of expression if a is true Expression elseexpr; // value of expression if a is false

Object model (heap layout) vs. type hierarchy (subtyping) AST for "a + b": (PlusOp) a (VarRef) b (VarRef) Class hierarchy for Expression: Expression PlusOp VarRef EqualOp CondExpr

Operations on Java expressions Java expressions Plus: 20 + 22 Variable reference: x Method call: foo(5) Conditional: b? 3 : 4 Equals: x == y Operations Typecheck Pretty-print Optimize

Type-checking an equality operation // typecheck "a == b" where a and b are arbitrary expressions Type tcequalsop(equalop e) { Type lefttype = tcexpression(e.lvalue); // type of a Type righttype = tcexpression(e.rvalue); // type of b if (lefttype!= ERROR_TYPE && righttype!= ERROR_TYPE && lefttype == righttype) { return BOOLEAN_TYPE; else { return ERROR_TYPE;

Type-checking a conditional expr // typecheck "a? b : c" Type tccondexpr(condexpr e) { Type condtype = tcexpression(e.condition); // type of a Type thentype = tcexpression(e.thenexpr); // type of b Type elsetype = tcexpression(e.elseexpr); // type of c if (condtype!= ERROR_TYPE && thentype!= ERROR_TYPE && elsetype!= ERROR_TYPE && condtype == BOOLEAN_TYPE && thentype == elsetype) { return thentype; else { return ERROR_TYPE;

Organizing operations on abstract syntax trees We know how to write code in each cell of this table: Objects CondExpr EqualOp Operations typecheck pretty-print Question: Should we group together the code for a particular operation or the code for a particular expression? (A separate issue: given an operation and an expression, how to select the proper piece of code to execute?)

Interpreter and procedural patterns Interpreter: collects code for similar objects, spreads apart code for similar operations Easy to add objects Hard to add operations An instance of the composite pattern Procedural: collects code for similar operations, spreads apart code for similar objects Easy to add operations Hard to add objects The visitor pattern is a variety of the procedural pattern OO style CondExpr Objects EqualOp Functional style CondExpr Objects EqualOp typecheck typecheck pretty-print pretty-print

Interpreter pattern typecheck pretty-print CondExpr Objects EqualOp Add a method to each class for each supported operation class Expression {... Type typecheck(); String prettyprint(); Dynamic dispatch chooses the right implementation, for a call like myexpr.typecheck() class EqualOp extends Expression { // "a == b"... Type typecheck() {... String prettyprint() {... class CondExpr extends Expression { // "a?b:c"... Type typecheck() {... String prettyprint() {...

Procedural pattern typecheck pretty-print CondExpr Objects EqualOp Create a class per operation, with a method per operand type class Typecheck { // typecheck "a?b:c" Type tccondexpr(condexpr e) { Type condtype = tcexpression(e.condition); // type of "a" Type thentype = tcexpression(e.thenexpr); // type of "b" Type elsetype = tcexpression(e.elseexpr); // type of "c" if ((condtype == BoolType) && (thentype == elsetype)) { return thentype; else { return ErrorType; // typecheck "a==b" Type tcequalop(equalop e) {... Given an expression, how to invoke the right implementation?

Definition of tcexpression class Typecheck {... Type tcexpression(expression e) { if (e instanceof PlusOp) { return tcplusop((plusop)e); else if (e instanceof VarRef) { return tcvarref((varref)e); else if (e instanceof EqualOp) { return tcequalop((equalop)e); else if (e instanceof CondExpr) { return tccondexpr((condexpr)e); else...... (in procedural pattern) Maintaining this code is tedious and error-prone. The cascaded if tests may to run slowly. Code duplication: this code is repeated in PrettyPrint and every other operation class. (Languages with pattern matching mitigate these problems.)

Visitor pattern: a variant of the procedural pattern Visitor encodes a traversal of a hierarchical data structure Nodes (objects in the hierarchy) accept visitors Visitors visit nodes (objects) class SomeExpression extends Expression { void accept(visitor v) { for each child of this node { child.accept(v); v.visit(this); n.accept(v) traverses the structure rooted at n, invoking v's operation class SomeVisitor { void visit(someexpression n) { perform work on n visit does the work on one element void visit(otherexpression n) { perform work on n What happened to all the instanceof operations?

Visitor pattern: example Objects class VarOp extends Expression { void accept(visitor v) { v.visit(this); class EqualsOp extends Expression { void accept(visitor v) { leftexp.accept(v); leftexp.accept(v); v.visit(this); class CondOp extends Expression { void accept(visitor v) { testexp.accept(v); thenexp.accept(v)` elseexp.accept(v); v.visit(this); class TypeCheckVisitor implements Visitor { void visit(equalsop e) { assert e.leftexp and e.rightexp have the same type void visit(plusop e) { assert e.leftexp and e.rightexp are numeric Operations Each operation has its cases together. Compiler error if a case is missing. class PrettyPrintVisitor implements Visitor { void visit(equalsop e) { print e void visit(plusop e) { print e

Visitor pattern: example Objects class VarOp extends Expression { void accept(visitor v) { v.visit(this); class EqualsOp extends Expression { void accept(visitor v) { leftexp.accept(v); leftexp.accept(v); v.visit(this); class CondOp extends Expression { void accept(visitor v) { testexp.accept(v); thenexp.accept(v)` elseexp.accept(v); v.visit(this); Overloading Operations class TypeCheckVisitor implements Visitor { void visit(equalsop e) { assert e.leftexp and e.rightexp have the same type void visit(plusop e) { assert e.leftexp and e.rightexp are numeric class PrettyPrintVisitor implements Visitor { void visit(equalsop e) { print e void visit(plusop e) { print e

Visitor pattern: example Objects class VarOp extends Expression { void accept(visitor v) { v.visitvar(this); class EqualsOp extends Expression { void accept(visitor v) { leftexp.accept(v); leftexp.accept(v); v.visitequals(this); class CondOp extends Expression { void accept(visitor v) { testexp.accept(v); thenexp.accept(v)` elseexp.accept(v); v.visitcond(this); Same behavior Operations class TypeCheckVisitor implements Visitor { void visitequals(equalsop e) { assert e.leftexp and e.rightexp have the same type void visitplus(plusop e) { assert e.leftexp and e.rightexp are numeric class PrettyPrintVisitor implements Visitor { void visitequals(equalsop e) { print e void visitplus(plusop e) { print e

Sequence of calls to accept and visit a.accept(v) b.accept(v) d.accept(v) v.visit(d) e.accept(v) v.visit(e) v.visit(b) c.accept(v) f.accept(v) v.visit(f) v.visit(c) v.visit(a) d e b f c a Sequence of calls to visit = depth-first (children before parents) How could we make it breadth-first (parents before children)? Requires a different visitor d b e a c f

Visitors are like iterators Each element of the data structure is presented in turn to the visit method Visitors have knowledge of the structure, not just the sequence

Calls to visit cannot communicate with one another 1. Use an auxiliary data structure 2. visit returns a value 3. Move more work into the visitor itself class Node { void accept(visitor v) { v.visit(this); class Visitor { void visit(node n) { for each child of this node { child.accept(v); perform work on n Information flow is clearer (if visitor depends on children) Traversal code repeated in all visitors (acceptor is extraneous)