IWETHEY v. 0.3.0 | TODO
1,095 registered users | 0 active users | 0 LpH | Statistics
Login | Create New User
IWETHEY Banner

Welcome to IWETHEY!

New OT: double dispatch?
I've seen the term, and used packages that said they implemented it, but missed the class where it was defined.
===

Implicitly condoning stupidity since 2001.
New double dispatch example
Double dispatch is used when you would really like to dispatch on two different objects at the same time.

Example: Suppose you were manipulating geometric shapes (Bryce will love this example), and you wanted to determine the intersection of two arbitrary shapes.
def process(shape1, shape2)\n  shape1.intersect(shape2)   # This is the first dispatch\nend
Now, the way an intersection is caculated is different depending on your shapes. For example, finding the intersection of two rectangles is done differently from finding the intersection of two circles, which in turn is different from a rectangle and a circle.

Now, if we know the type of one of the shapes, the algorithm is easy to write for any other shape. For example:
  class Rectangle\n    def intersect_rectangle(rect)\n      puts "Intersecting a Rectangle and a Rectangle"\n    end\n\n    def intersect_circle(circle)\n      puts "Intersecting a Rectangle and a Circle"\n    end\n  end\n\n  class Circle\n    def intersect_rectangle(rect)\n      puts "Intersecting a Circle and a Rectangle"\n    end\n\n    def intersect_circle(circle)\n      puts "Intersecting a Circle and a Circle"\n    end\n  end\n
Notice that each type knows how to intersect itself with both a circle and a rectangle.

Suppose I execute the code: rect.intersect(shape)? We dispatch to the retangle's intersection (this is the first dispatch). We don't know the type of shape, but we do know the type of self (which is a rectangle). Well, the problem is simple if we know one of the type (which we do). We just dispatch again. Here is the intersection code for rectangle:
  class Rectangle\n    def intersect(shape)\n      shape.intersect_rectangle(self)  # this is the second dispatch\n    end\n  end
The code for circle is a mirror image.
  class Circle\n    def intersect(shape)\n      shape.intersect_circle(self)  # this is also a second dispatch\n    end\n  end
Finally, we put it together:
  c1 = Circle.new\n  c2 = Circle.new\n  r1 = Rectangle.new\n  r2 = Rectangle.new\n\n  process(c1,c2)\n  process(r1, r2)\n  process(r1, c1)\n  process(c1, r1)
And the output is
  Intersecting a Circle and a Circle\n  Intersecting a Rectangle and a Rectangle\n  Intersecting a Circle and a Rectangle\n  Intersecting a Rectangle and a Circle
In short, double dispatch is a way of doing type discovery.

Advantages: it is fast and bounded. It takes just two polymorphic calls to resolve the types. A dynamic cast in Java or C++ is generally slower and depends on the shape of the inheritance tree.

Disadvantages: the number of dispatching methods grows with the square of the number of types to distinquish.
--
-- Jim Weirich jweirich@one.net [link|http://onestepback.org|http://onestepback.org]
---------------------------------------------------------------------
"Beware of bugs in the above code; I have only proved it correct,
not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)
New ahh, thanks
===

Implicitly condoning stupidity since 2001.
New Yep - its all through the numerics
That's the best example I know of. You have two numbers - you want to add them - but adding a couple of ints is different from adding an int and a float, or an int and a fraction (fractions are first class numbers in ST) or adding an int and a point....

In Java a small subset of what ought to be implemented in Number would look like:

class Number
{
Number add(Number n);
Number addInteger(Number n);
Number addFloat(Number n);

int intValue();
float floatValue();
}

class Integer extends Number
{
Number add(Number n) { n.addInteger(this); }
Number addInteger(Number n) { return new Integer(n.intValue() + this.intValue()); }
Number addFloat(Number n) { return new Float(n.floatValue() + this.floatValue()); }
}

class Float extends Number
{
Number add(Number n) { n.addFloat(this); }
Number addInteger(Number n) { return new Float(n.floatValue() + this.floatValue()); }
Number addFloat(Number n) { return new Float(n.floatValue() + this.floatValue()); }
}

So if I have a pair of Integers

Number n1 = new Integer(3);
Number n2 = new Integer(5);

Number n3 = n1.add(n2);
calls:
n1.add(n2) // neither concrete type is known here - within this call n1 (an integer) will identify its concrete type to n2
n2.addInteger(n1) // by telling it to addInteger to itself - n2 knows its type and does the right thing

Its very slick but the number of methods does indeed grow exponentially with the number of types. So its only really practical up to maybe 10 types or so.





Java is a joke, only it's not funny.

     --Alan Lovejoy
     Smalltalk GLORP => Ruby Criteria - (JimWeirich) - (6)
         Looks pretty cool - (tuberculosis) - (5)
             OT: double dispatch? - (drewk) - (3)
                 double dispatch example - (JimWeirich) - (1)
                     ahh, thanks -NT - (drewk)
                 Yep - its all through the numerics - (tuberculosis)
             Re: Looks pretty cool - (JimWeirich)

Whoa-ho-ho, nice shootin', Tex!
61 ms