Download Multi-mehtods

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts
no text concepts found
Transcript
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
2
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
3
The many faces of Multimethods

Design decision (responsibilities of classes)
Aspects
Compilation techniques + runtime system
Programming language

Expected to be highly popular



4
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 Blue wall – changes direction
Red ball hits a Yellow wall – Stops moving
Green ball hits a Blue wall – changes direction +
looses speed
Green ball hits a Yellow wall – wall disappears
5
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
6
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);
}
}
7
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_;
}
}
8
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
9
Motivation – The catch (2/2)

The collision rules depend on the dynamic
type of TWO objects:



At least two relevant classes: Wall, Ball



Formal argument w (static type: Wall)
Formal argument b (static type: Ball)
No obvious class to place the code at
Solution 1: Use instanceof
Solution 2: Use the “visitor” hack
10
Motivation – solution 1
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;
}
}


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
11
Motivation – solution 2
// 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); }
12
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

13
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; }
14
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
15
MultiJava (1/2)


Clifton, Leavens, Chambers, Millstein
First presented at OOPSLA 2000


Available at: http://multijava.sourceforge.net
Currently working on various enhancements
16
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
17
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”
}
18
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”
}
19
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
20
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
21
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();
“r-s”
System.out.println(both(r,s));
}
22
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();
“s-r”
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
23
Nice – example 3
Let’s add a circle class to the last program..

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"; }


This code will not compile !!
Pattern matching is incomplete:

E.g.: both(Circle,Circle) is not handled
24
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
25
Consequences

(We will use Nice for most code samples)
26
Open classes

Let’s define a function with an Object argument
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>”

=> Full support for “Open classes”

Any class can be expanded
27
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*
}
28
“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
29
Implementation

The magic behind multimethods..
30
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
31
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
if(s1 instanceof
return "r-r";
if(s1 instanceof
return "r-s";
if(s1 instanceof
return "s-r";
if(s1 instanceof
return "s-s";
}
}
{
apply(Shape s1, Shape s2) {
Rect && s2 instanceof Rect)
Rect && s2 instanceof Shape)
Shape && s2 instanceof Rect)
Shape && s2 instanceof Shape)
32
MultiJava – Implementation (2/2)

both$20 is a “Generic Function class”


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:


Provides the multi-dispatching functionality
Translates multimethod calls to invocations of apply() on the
proper generic function class
 both(..) is converted to:
both$20.apply(..)
Q: Drawbacks?
33
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
34
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());
Run
s14
if(o instanceof Shape)
both(o, o);
}
35
Overview of features

Basic features/properties






Additional features




Methods  functions
Open classes
Decoupling of state and behavior
Covariance
Symmetry
Value dispatch
Exact matching
Static dispatching of multimethods (“super”)
Not all features are supported by every implementation
36
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
37
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
38
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
39
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
40
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;
}
41
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
42
-The End-
43
Related documents