290 likes | 374 Views
SENG 531: Labs. TA: Brad Cossette brad.cossette@gmail.com cossette@cpsc.ucalgary.ca http://pages.cpsc.ucalgary.ca/~cossette/ Office Hours: Monday, Wednesday 3-4pm ICT 524. Labs This Week:. Monday Assignments Overview Polymorphism in OO Polymorphic Overloading Wednesday AST’s
E N D
SENG 531: Labs TA: Brad Cossette brad.cossette@gmail.com cossette@cpsc.ucalgary.ca http://pages.cpsc.ucalgary.ca/~cossette/ Office Hours: Monday, Wednesday 3-4pm ICT 524
Labs This Week: • Monday • Assignments Overview • Polymorphism in OO • Polymorphic Overloading • Wednesday • AST’s • Single vs. Double Dispatch • The Visitor Pattern
Assignment 1 Questions • You need to track each method invocation separately • e.g. don’t lump all moveBy() method invocations together • You should figure out the type each method is invoked on as a means of distinguishing between potentially similar method names
Assignment 1 Questions • Your output should be as informative as reasonably possible: • I should know which exactly which invocation/declaration you’re referring to at each point • The info available in a single node is very limited • Explore what data is available to you . . . • There are ways to augment this info . . .
Generics • Back in ye olden Java 1.4 days . . . public void oldPubCrawl( List pubs ) { for ( Iterator iii = pubs.iterator(); iii.hasNext(); ) { Bar current_bar = ( Bar )iii.next(); current_bar.drink(); current_bar.singVeryBadKaraoke(); } }
Generics • We have to cast, because List will take any object • Making List only take Bar objects means writing a specialized subclass public void oldPubCrawl( List pubs ) { for ( Iterator iii = pubs.iterator(); iii.hasNext(); ) { Bar current_bar = ( Bar )iii.next();
Generics Generics let us control what’s actually in a list… public void newestPubCrawl( List<Bar> pubs ) { for ( Iterator<Bar> iii = pubs.iterator(); iii.hasNext(); ) { Bar current_bar = iii.next(); current_bar.drink(); current_bar.singVeryBadKaraoke(); } } …without having separate customized classes.
Generics A better way to write this: public void newestPubCrawl( List<Bar> pubs ) { for ( Bar current_bar : pubs ) { current_bar.drink(); current_bar.singVeryBadKaraoke(); } }
Abstract Syntax Trees (AST) • Some compiler/language theory stuff: • Remember EBNF* form of context-free grammars? • When parsing a grammar, the rules when applied to some inputs can create a tree • If we ignore some syntactic symbols e.g. { }; etc. we can create an abstracted syntax tree . . . *Backus–Naur Form
Abstract Syntax Trees (AST) • Example: public class Foo { public int bar = 0; } public class FooBar { public static void main(String args[]) { Foo fighter = new Foo(); fighter.bar = 6; System.out.print( fighter.bar ); } } What could an AST for the outlined section look like?
Abstract Syntax Trees (AST) basic block statement statement = statement declaration create object statement field access Foo = fighter Foo System method invocation field access 6 out print fighter bar argument field access fighter bar
Abstract Syntax Trees (AST) • Key Points • You can recreate the source code from an AST • There’s not really an official standard for what an AST should look like This AST is different then the AST that Decaff will put out
AST: Why do you even care • Well, it’s part of the assignment
AST: Why do you even care • Well, it’s part of the assignment • Which is easier to search in? Why? • Source Code vs. AST? • Specifically, what is easier to find in an AST? • Program transformation (not in this course)
Suppose we have a tree of some sort: CPSC 331 – basic tree representation The Segueway: AST + Single Dispatch TreeNode argument TreeNode field access TreeNode TreeNode fighter bar
<<interface>> ITreeNode AbstractArgument ObjectReference FieldReference FieldAccess The Segueway: AST + Single Dispatch • Subclass TreeNode accordingly has Question: ITreeNode should probably be an Abstract class, not an Interface. Why?
AST Problem: Tree Traversal • Basic algorithm is easy • Example AST uses an in-order traversal • Others may use post-order • BUT! At each node, you need: • Code to determine what the node is • Code to handle that node’s children
AST Problem: Tree Traversal Why won’t this work? public abstract class AbstractTreeNode { protected AbstractTreeNode parent = null; protected List<AbstractTreeNode> children = null; protected String data = ""; }
AST Problem: Tree Traversal public class TreeTraversal { private AbstractTreeNode root_node = null; public TreeTraversal( AbstractTreeNode root ) { this.root_node = root; } public void traverse() { traverse( this.root_node ); } //Continued on Next Slide }
AST Problem: Tree Traversal public class TreeTraversal { //Continued protected void traverse( AbstractTreeNode node ) { if ( null != node.children && node.children.size() > 0 ) traverse( node.children.get( 0 ) ); System.out.println( "AbstractTreeNode: " + node.data ); if ( null != node.children && node.children.size() > 1 ) traverse( node.children.get( 1 ) ); } protected void traverse( Argument node ) { } protected void traverse( FieldAccess node ) { } protected void traverse( FieldReference node ) { } protected void traverse( ObjectReference node ) { } }
AST Problem: Tree Traversal public static void main( String args[] ) { Argument root = new Argument( "" ); FieldAccess fa = new FieldAccess( "." ); root.children.add( fa ); ObjectReference or = new ObjectReference( "fighter" ); FieldReference fr = new FieldReference( "bar" ); fa.children.add( or ); fa.children.add( fr ); TreeTraversal printer = new TreeTraversal( root ); printer.traverse(); } Output: AbstractTreeNode: fighter AbstractTreeNode: . AbstractTreeNode: bar AbstractTreeNode:
Tree Traversal + Single Dispatch • So we have two problems: • We need a common supertype to support a tree that we can traverse without custom code • We still need to have specific subclasses at each node to reflect different data • Java is single dispatch • How do we work around this?
Double Dispatch • Single Dispatch • The type of an object is calculated at compile time • Double Dispatch • The object’s type is determined at run-time • This is NOT duck-typing! • What’s the difference?
Double Dispatch • How do you simulated Double Dispatch? • Reflection • object instanceof X • Object.getClass() • Are there problems with this? • The Visitor design pattern • Simulate double dispatch by splitting responsibility
The Visitor Design Pattern • Simulates Double Dispatch: • The Visitor class expects an interface that it can call to transfer control • The called class is responsible for calling the appropriate method on the Visitor
The Visitor Design Pattern • The Visitor’s Target public interface class IVisitable { public void accept( AbstractVisitor visitor ); } • The Visitor “gives itself” to the class it visits • This still lets us take advantage of the common superclass
The Visitor Design Pattern • How to use the Visitor public class FieldAccess extends Argument implements IVisitable { //snip public void accept( AbstractVisitor visitor ) { left_child.accept( visitor ); visitor.visit( this ); //this = FieldAccess type object right_child.accept( visitor ); } } • Note that the call-back to the visitor now explicitly refers to the subclass type
The Visitor Design Pattern • Writing the Visitor public abstract class AbstractVisitor { //snip public void visit( FieldAccess object ) { //do stuff } } • Now we can take advantage of polymorphic overloading, without Java’s single dispatch model being a problem.
Labs Next Week: • Monday • Help with Assignment #1 • Wednesday • Help with Assignment #1