July 21, 2004
I assume that you are aware how you can hand-code a multimethod?

I agree that this would be very cool to be implemented automatically.

nail wrote:
> What about multimethods? It would be fine if I can do following:
> 
> class Figure { ... }
> class Rect : Figure { ... }
> class Circle: Figure { ... }
> class Triangle: Figure { ... }
> 
> float IntersectionSquare(Rect r, Circle c) // (1)
> { ... }
> 
> float IntersectionSquare(Circle r, Circle c) // (2)
> { ... }
> 
> float IntersectionSquare(Rect r, Figure f) // (3)
> { ... }
> 
> multimethod float IntersectionSquare(Figure a, Figure b);
> 
> void main()
> {
> Figure r = new Rect;
> Figure c = new Circle;
> Figure t = new Triangle;
> float sq;
> 
> sq = IntersectionSquare(r, c); // (1) called
> sq = IntersectionSquare(c, c); // (2) called
> sq = IntersectionSquare(r, t); // (3) called
> }
> 
> Any facts against?
> 
> 

July 21, 2004
In article <cdkc7v$2217$1@digitaldaemon.com>, Russ Lewis says...
>
>I assume that you are aware how you can hand-code a multimethod?
>
>I agree that this would be very cool to be implemented automatically.
>
>nail wrote:
>> What about multimethods? It would be fine if I can do following:
>> 
>> class Figure { ... }
>> class Rect : Figure { ... }
>> class Circle: Figure { ... }
>> class Triangle: Figure { ... }
>> 
>> float IntersectionSquare(Rect r, Circle c) // (1)
>> { ... }
>> 
>> float IntersectionSquare(Circle r, Circle c) // (2)
>> { ... }
>> 
>> float IntersectionSquare(Rect r, Figure f) // (3)
>> { ... }
>> 
>> multimethod float IntersectionSquare(Figure a, Figure b);
>> 
>> void main()
>> {
>> Figure r = new Rect;
>> Figure c = new Circle;
>> Figure t = new Triangle;
>> float sq;
>> 
>> sq = IntersectionSquare(r, c); // (1) called
>> sq = IntersectionSquare(c, c); // (2) called
>> sq = IntersectionSquare(r, t); // (3) called
>> }
>> 
>> Any facts against?
>> 
>> 
>

Hand-coded multimethods are posible. But I have to use bulky auxiliary constructions a-la dispatcher. This makes code less readable and more comlicated. Integrated feature will resolve this problem in elegant way.

Sean Kelly <sean@f4.ca> says...
> Why the new keyword?  Doesn't D handle overload resolution just fine without it?

No, it would not. If I have:

class A {}
class B : A {}
void foo(A a1, A a2) { std.c.printf("A!"); }
void foo(B b1, B b2) { std.c.printf("B!"); }
void main()
{
A x = new B;
A y = new B;
foo(x, y);
}

Program will print "A!" that is not what I want.


July 21, 2004
In article <cdjekg$1ki0$1@digitaldaemon.com>, Sean Kelly says...
>
>Why the new keyword?  Doesn't D handle overload resolution just fine without it?

Nope. There is no overload resolution at runtime. And that's what multimethods are all about.


July 21, 2004
>What about multimethods? It would be fine if I can do following:
>
>class Figure { ... }
>class Rect : Figure { ... }
>class Circle: Figure { ... }
>class Triangle: Figure { ... }
>
>float IntersectionSquare(Rect r, Circle c) // (1)
>{ ... }
>
>float IntersectionSquare(Circle r, Circle c) // (2)
>{ ... }
>
>float IntersectionSquare(Rect r, Figure f) // (3)
>{ ... }
>
>multimethod float IntersectionSquare(Figure a, Figure b);
>
>void main()
>{
>Figure r = new Rect;
>Figure c = new Circle;
>Figure t = new Triangle;
>float sq;
>
>sq = IntersectionSquare(r, c); // (1) called
>sq = IntersectionSquare(c, c); // (2) called
>sq = IntersectionSquare(r, t); // (3) called
>}
>
>Any facts against?
>
I proposed something similar a few days ago. My version didn't need a new keyword and was more general.

This ability isn't neccessarilly restricted to multimethods. You could use it for any kind of runtime dispatching.

To use your notation:

float handle(HandleDerived1 foo)
{ ... }
float handle(HandleDerived2 foo)
{ ... }

multimethod float handle(HandleBase foo);

You see, the name multimethod is very confusing here.

-- Matthias Becker


July 21, 2004
In article <cdlc89$2gai$1@digitaldaemon.com>, Matthias Becker says...
>
>
>>What about multimethods? It would be fine if I can do following:
>>
>>class Figure { ... }
>>class Rect : Figure { ... }
>>class Circle: Figure { ... }
>>class Triangle: Figure { ... }
>>
>>float IntersectionSquare(Rect r, Circle c) // (1)
>>{ ... }
>>
>>float IntersectionSquare(Circle r, Circle c) // (2)
>>{ ... }
>>
>>float IntersectionSquare(Rect r, Figure f) // (3)
>>{ ... }
>>
>>multimethod float IntersectionSquare(Figure a, Figure b);
>>
>>void main()
>>{
>>Figure r = new Rect;
>>Figure c = new Circle;
>>Figure t = new Triangle;
>>float sq;
>>
>>sq = IntersectionSquare(r, c); // (1) called
>>sq = IntersectionSquare(c, c); // (2) called
>>sq = IntersectionSquare(r, t); // (3) called
>>}
>>
>>Any facts against?
>>
>I proposed something similar a few days ago. My version didn't need a new keyword and was more general.
>
>This ability isn't neccessarilly restricted to multimethods. You could use it for any kind of runtime dispatching.
>
>To use your notation:
>
>float handle(HandleDerived1 foo)
>{ ... }
>float handle(HandleDerived2 foo)
>{ ... }
>
>multimethod float handle(HandleBase foo);
>
>You see, the name multimethod is very confusing here.
>
>-- Matthias Becker
>
>


I see nothing confusing in the examle above. If you mean that handle(x), where x
is realy HandleBase is undefined then exception must be thrown. Or maybe more
acceptable way - throw compile-time error if such method for base class is
undefined.
I don't impose this kind of notation. I simply said that multimethods are
powerful things and having them integrated in language would be very and very
nicely.


July 21, 2004
nail wrote:
> What about multimethods? It would be fine if I can do following:
> 
> class Figure { ... }
> class Rect : Figure { ... }
> class Circle: Figure { ... }
> class Triangle: Figure { ... }
> 
> float IntersectionSquare(Rect r, Circle c) // (1)
> { ... }
> 
> float IntersectionSquare(Circle r, Circle c) // (2)
> { ... }
> 
> float IntersectionSquare(Rect r, Figure f) // (3)
> { ... }
> 
> multimethod float IntersectionSquare(Figure a, Figure b);
> 
> void main()
> {
> Figure r = new Rect;
> Figure c = new Circle;
> Figure t = new Triangle;
> float sq;
> 
> sq = IntersectionSquare(r, c); // (1) called
> sq = IntersectionSquare(c, c); // (2) called
> sq = IntersectionSquare(r, t); // (3) called
> }
> 
> Any facts against?

Dynamic dispatch can be implemented by setting up an associative array that maps ClassInfo to a delegate, and writing a method that indexes the classinfo of its argument and calls.

The trick, then, becomes working out some automatic (or nearly automatic) way of filling up that associative array. :)

 -- andy
July 21, 2004
In article <cdlc1g$2g7g$1@digitaldaemon.com>, Matthias Becker says...
>
>In article <cdjekg$1ki0$1@digitaldaemon.com>, Sean Kelly says...
>>
>>Why the new keyword?  Doesn't D handle overload resolution just fine without it?
>
>Nope. There is no overload resolution at runtime. And that's what multimethods are all about.

Please excuse me while I kick myself :)  Thanks for the clarification.

BTW, I agree that multimethods would be a great feature to have, provided the syntax were fitting.  I don't like the idea of a new keyword in this case.


Sean


July 21, 2004
In article <cdm3hu$2qqb$1@digitaldaemon.com>, Andy Friesen says...
>> Any facts against?
>
>Dynamic dispatch can be implemented by setting up an associative array that maps ClassInfo to a delegate, and writing a method that indexes the classinfo of its argument and calls.
>
>The trick, then, becomes working out some automatic (or nearly automatic) way of filling up that associative array. :)

Actually, I started work on a solution for this the beginning of the thread. The result is almost exactly what you propose here Andy. ( well, mostly ) ;)

Take a look at the example in main, it pretty much handles the proposed case menioned at the beginning of the thread.

Personally, I hate template-heavy solutions but that was the only way I could figure out how to capture the call signatures of each delegate.  The only place type safety breaks is in the return value, which is broken at the moment.

Basically the interesting stuff is all in the Delegate class templates.  Each Delegate takes a return type and n types that correspond to the parameters of a function.  The template constructor requires a valid delegate that matches this signature.  The class itself exposes several methods for calling the underlying method, as well as validating the types of the passed parameters in a strict or relaxed fashion.

The MultimethodDelegate itself maintains a list of abstract delegates for call dispatching.  When a call is made via opCall(...) it looks for the first best match and forwards the arguments to that delegate.

Another drawback is that the delegate templates are specialized by the number of parameters and the return type.  So Delegate0 has no args, Delegate1 has one, Delegate2 has two args... the rest (Delegate3 on up) are left as an exercise to the developer.  As far as I know, this is an age-old limitation to Templates that comes from D's C++ heritage.

As a bonus, I threw in some extra helper templates and a MulticastDelegate that I was finally able to finish thanks to the ideas put forward here in the NG.

If you have any fixes/changes/suggestions, please post them back here so we can all benefit. :)

- Pragma


July 21, 2004
Alternate link: http://www.djsolaries.com/pragma/misc/multimethod.d


July 22, 2004
>I see nothing confusing in the examle above. If you mean that handle(x), where x
>is realy HandleBase is undefined then exception must be thrown. Or maybe more
>acceptable way - throw compile-time error if such method for base class is
>undefined.
>I don't impose this kind of notation. I simply said that multimethods are
>powerful things and having them integrated in language would be very and very
>nicely.
>
MULTImethod. This means that you have methods whith is bound to multiple objects instead of only one. In my example I used it on only one object, so the name multimethod is very confusing.

Have you read my proposal?

// this is a fallback function bool intersect(Shape foo, Shape bar) {...}

// Intersection of Triangle and Square
bool intersect(Shape @ Triangle foo, Shape @ Square bar)
{...}

// Intersection of Square and Triangle
bool intersect(Shape @ Square foo, Shape @ Triangle bar)
{...}

// Intersection of two Squares
bool intersect(Shape @ Square foo, Shape @ Square bar)
{...}

You have one compiletimetype (here Shape) and one runtimetype (Here Triangle and
Square).


You can do things you can't with your version:

class Base1{}
class Base2{}
class Derived1FromBase1 : Base1 {}
class Derived2FromBase1 : Base1 {}
class Derived1FromBase2 : Base2 {}
class Derived2FromBase2 : Base2 {}

void func (Base1 @ Derived1FromBase1 x)
{...}

void func (Base1 @ Derived2FromBase1 x)
{...}

void func (Base2 @ Derived1FromBase2 x)
{...}

void func (Base2 @ Derived2FromBase2 x)
{...}


So you can do:

Base1 b1 = new Derived2FromBase1();
func (b1);

Base2 b2 = new Derived1FromBase2();
func (b2);



I don't need a new keyword and my version is more flexible. My version allows a fallback-function i none of the derived forms fits, ... .

I don't want to sound arogant.

-- Matthias Becker