1 / 43

Multimethods

Multimethods. Itay Maman Demo. Multimethods (1/2). A dynamic-dispatch mechanism The executed method is selected by the dynamic type of one (or more) argument(s) virtual methods in Java/C++ are all “ SingleMethods ” Related terms: Multi-dispatch Binary-dispatch. Multimethods (2/2).

valmai
Download Presentation

Multimethods

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Multimethods Itay Maman Demo

  2. Multimethods (1/2) • A dynamic-dispatch mechanism • The executed method is selected by the dynamic type of one (or more) argument(s) • virtual methods in Java/C++ are all “SingleMethods” • Related terms: • Multi-dispatch • Binary-dispatch

  3. Multimethods (2/2) • Single-method dispatching as a mapping: • (t, mid) -> mp • t - The dynamic type of the receiver • mid – Method id • mp – Pointer to selected method • Multimethod dispatching: • (t1, t2, … tn, mid) -> mp

  4. The many faces of Multimethods • Design decision (responsibilities of classes) • Aspects • Compilation techniques + runtime system • Programming language • Expected to be highly popular

  5. Motivation • The bouncing ball simulation: • A 2d plain with walls • Two kinds of walls: Blue, Yellow • Two kinds of balls: Red, Green • Collision rules • Red ball hits a Bluewall – changes direction • Red ball hits a Yellowwall – Stops moving • Green ball hits a Bluewall – changes direction + looses speed • Green ball hits a Yellowwall – wall disappears

  6. Motivation • The OO model: • Vector of Balls, Walls • Abstract class Wall • Maintains location, color • Has an active/not active flag • Two direct sub-classes: WallX, WallY • StickyWallX is a sub-class of WallX • Class Ball • Maintains location, color • Maintains vx, vy (velocity in each axis) • One sub-class: PowerBall

  7. Motivation – Wall // file: Wall.java public abstract class Wall { private Rectangle rect_; private Color color_; public boolean active_ = true; public Wall(int x, int y, int w, int h, Color color) { color_ = color; rect_ = new Rectangle(x, y, w, h); } public void draw(Graphics g) { if(!active_) return; g.setColor(color_); g.fillRect(rect_.x, rect_.y, rect_.width, rect_.height); } public boolean contains(double x, double y) { return active_ && rect_.contains((int) x, (int) y); } }

  8. Motivation – Ball // file: Ball.java public class Ball { private static double chooseVelocity() { .. } public double vx_ = chooseVelocity(); public double vy_ = chooseVelocity(); public double x_ = 50; public double y_ = 50; public Color color_ = Color.RED; public void draw(Graphics g) { g.setColor(color_); g.fillArc((int) x_ - 5, (int) y_ - 5, 10, 10, 0, 360); } public void move() { x_ += vx_; y_ += vy_; } }

  9. Motivation – The catch (1/2) // Precondition: // w.contains(b.x_, b.y_) == true // // Postcondition: // The state of b, w has changed according // to the simulation’s collision rules // void collision(Wall w, Ball b) { // ? ? ? ? // ? ? ? ? } • This function/method should implement the “collision rules” • A plain virtual method will not do

  10. Motivation – The catch (2/2) • The collision rules depend on the dynamic type of TWO objects: • Formal argument w (static type: Wall) • Formal argument b (static type: Ball) • At least two relevant classes: Wall, Ball • No obvious class to place the code at • Solution 1: Use instanceof • Solution 2: Use the “visitor” hack

  11. Motivation – solution 1 • Pros: • Code is located in one place • Cons: • A Complex chain of if-else • No alert if a case was not handled • No alert if we change the hierarchy • Order is significant void collision(Wall w, Ball ball) { if(w instanceof WallX) { if(ball instanceof Ball) b.vy_ *= -1; else if(ball instanceof PowerBall) b.vy_ *= -0.9; } if(w instanceof WallY) { if(ball instanceof Ball) b.vx_ *= -1; else if(ball instanceof PowerBall) b.vx_ *= -0.9; } if(w instanceof StickyWallX) { if(ball instance of Ball) b.vy_ = b.vx_ = 0; else if(ball instnaceof PowerBall) w.active_ = false; } }

  12. Motivation – solution 2 // file: Wall.java class Wall { .. abstract void hit(Ball b); abstract void hit(PowerBall pb); } // file: Wall.java class Wall { .. abstract void hit(Ball b); abstract void hit(PowerBall pb); } // file: Ball.java void collide(Wall w) { w.hit(this); } // file: PowerBall.java void collide(Wall w) { w.hit(this); } // file: WallX.java void hit(Ball b) { b.vy_ *= -1; } void hit(PowerBall b) { b.vy_ *= -0.9; } // file: StickyWallX.java void hit(Ball b) { b.vx_ = b.vy_ = 0; } void hit(PowerBall b) { active_ = false; } // file: BouncingBallDemo.java void collision(Wall w, Ball b) { b.collide(w); }

  13. Motivation – solution 2 (cont’d) • Pros: • Order is less significant • Some compiler alerts • Cons: • Code is highly scattered • Reduced cohesion, increased coupling • Many methods must be implemented

  14. Motivation – A Nicer solution // file: BouncingBallDemo.nice void collision(Wall w, Ball b); collision(WallX w, Ball b) { b.vy_ *= -1; } collision(WallY w, Ball b) { b.vx_ *= -1; } collision(StickyWallX w, Ball b) { b.vx_ = b.vy_ = 0; } collision(WallX w, PowerBall b) { b.vy_ *= -0.9; } collision(WallY w, PowerBall b) { b.vx_ *= -0.9; } collision(StickyWallX w, PowerBall b) { w.active_ = false; }

  15. Questions • Where (in the source code) can a multimethod be defined? • Just like a virtual method? • File scope? • Within a dedicated class? • Does a multimethod have a “this” reference? • Policy for selecting the “best” match • Implementation • Much more complicated than a virtual method dispatch

  16. MultiJava (1/2) • Clifton, Leavens, Chambers, Millstein • First presented at OOPSLA 2000 • Available at: http://multijava.sourceforge.net • Currently working on various enhancements

  17. MultiJava (2/2) • An extension to Java • A legal Java program is also a MultiJava program • Compilation/execution • The MultiJava compiler replaces javac • Produces standard .class files • No linking phase • Any standard JVM can run the program • Excluding J2SE 5.0

  18. MultiJava – example 1 public class Shape { public String both(Shape s) { return "s-s"; } public String both(Shape@Rect r) { return "s-r"; } } public class Rect extends Shape { public String both(Shape s) { return "r-s"; } public String both(Shape@Rect r) { return "r-r"; } } public static void main(String args[]) { Shape s = new Shape(); Shape r = new Rect(); System.out.println(s.both(s)); System.out.println(s.both(r)); System.out.println(r.both(s)); System.out.println(r.both(r)); } “s-s” “s-r” “r-s” “r-r”

  19. MultiJava – example 2 public static class Shape { } // file: Shape.java public static class Rect extends Shape { } // file: Rect.java // file: something.java public static String both(Shape s1, Shape s2) { return "s-s"; } public static String both(Shape s, Shape@Rect r) { return "s-r"; } public static String both(Shape@Rect r, Shape s) { return "r-s"; } public static String both(Shape@Rect r1, Shape@Rect r2) { return "r-r"; } public static void main(String args[]) { Shape s = new Shape(); Shape r = new Rect(); System.out.println(both(s,s)); System.out.println(both(s,r)); System.out.println(both(r,s)); System.out.println(both(r,r)); } “s-s” “s-r” “r-s” “r-r”

  20. Nice (1/2) • Bonniot, Keller, Barber • Not an academic work • Mentioned in several articles (Scala) • Available at: http://nice.sourceforge.net • A java-like programming language • Not an extension of Java • Paradigms: OO, Functional

  21. Nice (2/2) • Besides multimethods, offers additional features: • Functions are 1st class values, anonymous functions • Tuples • Generics • Named parameters • Limited inference • Compilation/Execution • The compiler (nicec) produces executables (jar files) • Any standard JVM can run the program • Has a linking phase • Compilation unit: package

  22. Nice – example 1 public class Shape { } public class Rect extends Shape { } String both(Shape a1, Shape a2) { return "s-s"; } both(Shape a1, Rect a2) { return "s-r"; } both(Rect a1, Shape a2) { return "r-s"; } both(Rect a1, Rect a2) { return "r-r"; } public void main(String[] args) { Shape s = new Shape(); Shape r = new Rect(); System.out.println(both(r,s)); } “r-s”

  23. Nice – example 2 public abstract class Shape { } public class Rect extends Shape { } String both(Shape a1, Shape a2); both(Shape a1, Rect a2) { return "s-r"; } public void main(String[] args) { Shape r1 = new Rect(); Shape r2 = new Rect(); System.out.println(both(r1,r2)); } • No need to implement both(Shape, Shape) • Q: How is it possible? • A: Linking • Dispatching is checked at link-time “s-r”

  24. Nice – example 3 • Let’s add a circle class to the last program.. • This code will not compile !! • Pattern matching is incomplete: • E.g.: both(Circle,Circle) is not handled public abstract class Shape { } public class Rect extends Shape { } public class Circle extends Shape { } String both(Shape a1, Shape a2); both(Shape a1, Rect a2) { return "s-r"; }

  25. Nice – Methods vs. Functions public class Rect { int w = 0; int h = 0; public int area() { return w * h; } } public void set(Rect r, int w, int h) { r.h = h; r.w = w; } public void main(String[] args) { Rect r = new Rect(); r.set(10,10); System.out.println(r.area()); set(r,10,20); System.out.println(area(r)); } • Two equivalent forms for method/function invocation • x.f(y,z) • f(x,y,z) • Every file-scope function is also a method • But, there is no “this” in file-scope functions

  26. Consequences • (We will use Nice for most code samples)

  27. Open classes • Let’s define a function with an Object argument • => Full support for “Open classes” • Any class can be expanded public void show(Object o) { System.out.println(‘<‘ + o.getClass() + ":" + o + ‘>‘); } public void main(String[] args) { String s = "abc"; s.show(); } “<class java.lang.String:abc>”

  28. Playing with two arguments • Printer.show() displays the hash-code of an Object • StringPrinter.show()displays the length of a String public class Printer { void show(Object o) { // *1* System.out.println("Hashcode=" + o.hashCode()); } } public class StringPrinter extends Printer { void show(String s) { // *2* System.out.println("Len=" + s.length()); } } public void main(String[] args) { Printer p = new StringPrinter(); p.show(new java.util.Date()); // Invokes *1* p.show("abc"); // Nice: Invokes *2*. Java: Invokes *1* }

  29. “Best match” policy String both(Shape a1, Shape a2) = "s-s"; // *1* both(Rect a1, Shape a2) = "r-s"; // *2* both(Shape a1, Circle a2) = "s-c"; // *3* both(new Rect(), new Circle()); // Invokes ??? • Which implementation is invoked? • Asymmetric multimethods: *2* • Order of parameters is significant • Not intuitive • Symmetric multimethods: None (compiler error) • Order is insignificant • May yield ambiguity (see the above sample) • Used by MultiJava, Nice

  30. Implementation • The magic behind multimethods..

  31. Reminder: Java’s single-dispatch • Each class has a dispatch table with N entries • Created by the compiler • N– Number of “messages” the class can receive • Each entry specifies the “address” of the relevant method • When the .class file is generated, N is known • In multimethods: • N is not known

  32. MultiJava – Implementation (1/2) // file: something.java public static String both(Shape s1, Shape s2) { return "s-s"; } public static String both(Shape s, Shape@Rect r) { return "s-r"; } public static String both(Shape@Rect r, Shape s) { return "r-s"; } public static String both(Shape@Rect r1, Shape@Rect r2) { return "r-r"; } public class both$20 { public static void apply(Shape s1, Shape s2) { if(s1 instanceof Rect && s2 instanceof Rect) return "r-r"; if(s1 instanceof Rect && s2 instanceof Shape) return "r-s"; if(s1 instanceof Shape && s2 instanceof Rect) return "s-r"; if(s1 instanceof Shape && s2 instanceof Shape) return "s-s"; } }

  33. MultiJava – Implementation (2/2) • both$20 is a “Generic Function class” • Provides the multi-dispatching functionality • Generated automatically by the compiler • In the previous example, both$20 is generated for both(Shape, Shape) • Is used for all versions of both() which are a specialization of both(Shape, Shape) • Call site translation by the compiler: • Translates multimethod calls to invocations of apply() on the proper generic function class • both(..) is converted to: both$20.apply(..) • Q: Drawbacks?

  34. MultiJava – the flaw • Splitting the definition • Let’s define both() in two compilation units: • Something.java, SomethingElse.java public static class Shape { } // file: Shape.java public static class Rect extends Shape { } // file: Rect.java // file: Something.java public static String both(Shape s1, Shape s2) { return "s-s"; } public static String both(Shape s, Shape@Rect r) { return "s-r"; } // file: SomethingElse.java public static String both(Shape@Rect r, Shape s) { return "r-s"; } public static String both(Shape@Rect r1, Shape@Rect r2) { return "r-r"; } • This code will NOT compile • The compiler will not regenerate the generic function class • Separate compilation principle

  35. Nice – the flaw • Implementation of multimethods in Nice: • Multimethod dispatching code is created during linking • All declared types are known at link-time • Thus, Pattern-matching can make sure all cases are handled • Q: Where is the flaw? public abstract class Shape { } public class Rect extends Shape { } public toString(Shape s) { return "Shape/" + s.getClass(); } String both(Shape l, Shape r); both(Rect l, Rect r) { return "r-r"; } public void main(String[] args) { Object o = Class.forName("s14.Circle").newInstance(); System.out.println("Object=" + o.toString()); if(o instanceof Shape) both(o, o); } Run s14

  36. Overview of features • Basic features/properties • Methods  functions • Open classes • Decoupling of state and behavior • Covariance • Symmetry • Additional features • Value dispatch • Exact matching • Static dispatching of multimethods (“super”) • Not all features are supported by every implementation

  37. Summary • MultiJava • Simpler compilation model • Restrictions on the definitions of multimethods • The less-specialized method must be implemented • Nice • Complex compilation • Uses pattern matching => Compile-time safety • Dynamic loading of classes yields dispatch errors at run-time

  38. Multimethods in ML (1/3) • Definition of Multimethods: Dispatching mechanism where the executed method is selected by the dynamic type of one (or more) argument(s) • Q:Is it possible to create a similar mechanism in ML? • First approach: “A language without virtual methods cannot offer multimethods” • Second approach: Let’s change the definition (!) • Multimethods: Dispatching mechanism where the executed function is selected by the concrete type of one (or more) polymorphic values

  39. Multimethods in ML (2/3) • ML support polymorphism: A single variable can hold values of different types • Datatype (AKA: Variant record) -datatype Shape = Circle of real | Rect of real*real; -fun area(Circle(r)) = r*r*3.14 | area(Rect(w,h)) = w*h; val area = fn : Shape -> real • The area() function is analogous to an area() method defined by class Shape

  40. Multimethods in ML (3/3) • Now, let’s define our both() function.. • both() accepts a tuple of Shape*Shape • Uses Pattern-matching to select correct implementation -datatype Shape = Circle of real | Rect of real*real; -fun both(Circle(_), Circle(_)) = "c-c" | both(Circle(_), Rect(_,_)) = "c-r" | both(Rect(_,_), Circle(_)) = "r-c" | both(Rect(_,_), Rect(_,_)) = "r-r"; val both = fn : Shape * Shape -> string

  41. ML style multimethods in C++ struct Circle { }; struct Rect { }; typedef Variant<Circle,Rect> Shape; struct Both { void action(Circle a1, Circle a2) const { cout << "c-c"; } void action(Circle a1, Rect a2) const { cout << "c-r"; } void action(Rect a1, Circle a2) const { cout << "r-c"; } void action(Rect a1, Rect a2) const { cout << "r-r"; } }; int main() { Shape c = Circle(); Shape r = Rect(); dispatch(c,r,Both()); reutrn 0; }

  42. References • Curtis, Leavens, Chambers and Todd, MultiJava: Modular open classes and symmetric Multiple Dispatch for Java, OOPSLA 2000 • Baker and Hsie, Maya: Multiple-Dispatch Syntax Extension in Java, PLDI 2002 • Dutchyn, Szafron, Bromling and Holst, Multi-Dispatch in the Java virtual machine: design and implementation, COOTS 2001 • Bonniot, Keller and Barber, The Nice user’s manual

  43. -The End-

More Related