From: Jochen Schmidt
Subject: Multimethods
Date: 
Message-ID: <8oeshi$alns4$1@ID-22205.news.cis.dfn.de>
An old question I never dared to ask...

I know multimethods have a lot of further features but the most stated
difference to single-methods is that multimethods specialize an all of its 
arguments.
But where is the difference at this point to e.g. some overloaded global
C++ functions?

e.g.:

#include <iostream.h>

class A {};
class B {};
class C : public A {};

void foo(A a, A b) { cout << "(A A)" << endl;}
void foo(B a, B b) { cout << "(B B)" << endl;}
void foo(A a, B b) { cout << "(A B)" << endl;}
void foo(B a, A b) { cout << "(B A)" << endl;}
//void foo(C a, B b) { cout << "(C B)" << endl;}

int main()
{
  A a;
  B b;
  C c;
  
  foo(a,a);
  foo(b,b);
  foo(a,b);
  foo(b,a);
  foo(c,b);

  return 0;
}


This is similar to the most stated behavior of multimethods - but that 
cannot be the whole game can it?

Note: I'm not arguing that C++'s  global functions are better/equal to CL
generic-functions but that this behavior of CL-Generic functions is the 
first example I ever see if someone gives an explanation of what 
multimethods are.

confused...
Jochen Schmidt
···@dataheaven.de


-- 

From: Frank A. Adrian
Subject: Re: Multimethods
Date: 
Message-ID: <HKGq5.1055$Z83.452949@news.uswest.net>
(a) Multimethods dispatch on required parameters.  They do not look at
&optional, &rest, or &key parameters (nor all the rest).

(b) Multi-method dispatch differs from C++ overloading in that (i) method
dispatch is performed dynamically, using the actual type of the parameter,
rather than what the compiler "thinks" the parameter is at compile time and
(ii) the use of method combinations is much more flexible than C++'s (only)
choice of "call the next method".

faa
"Jochen Schmidt" <···@dataheaven.de> wrote in message
···················@ID-22205.news.cis.dfn.de...
> An old question I never dared to ask...
>
> I know multimethods have a lot of further features but the most stated
> difference to single-methods is that multimethods specialize an all of its
> arguments.
> But where is the difference at this point to e.g. some overloaded global
> C++ functions?
>
> e.g.:
>
> #include <iostream.h>
>
> class A {};
> class B {};
> class C : public A {};
>
> void foo(A a, A b) { cout << "(A A)" << endl;}
> void foo(B a, B b) { cout << "(B B)" << endl;}
> void foo(A a, B b) { cout << "(A B)" << endl;}
> void foo(B a, A b) { cout << "(B A)" << endl;}
> //void foo(C a, B b) { cout << "(C B)" << endl;}
>
> int main()
> {
>   A a;
>   B b;
>   C c;
>
>   foo(a,a);
>   foo(b,b);
>   foo(a,b);
>   foo(b,a);
>   foo(c,b);
>
>   return 0;
> }
>
>
> This is similar to the most stated behavior of multimethods - but that
> cannot be the whole game can it?
>
> Note: I'm not arguing that C++'s  global functions are better/equal to CL
> generic-functions but that this behavior of CL-Generic functions is the
> first example I ever see if someone gives an explanation of what
> multimethods are.
>
> confused...
> Jochen Schmidt
> ···@dataheaven.de
>
>
> --
>
From: Frank A. Adrian
Subject: Re: Multimethods
Date: 
Message-ID: <rZGq5.1107$Z83.460287@news.uswest.net>
"Frank A. Adrian" <·······@uswest.net> wrote in message
··························@news.uswest.net...
> (a) Multimethods dispatch on required parameters.  They do not look at
> &optional, &rest, or &key parameters (nor all the rest).

A slight correction.  They do not look at the other arguments for
dispatching purposes.  Of course, they do use the other parameters during
execution of the generic function.
>
> (b) Multi-method dispatch differs from C++ overloading in that (i) method
> dispatch is performed dynamically, using the actual type of the parameter,
> rather than what the compiler "thinks" the parameter is at compile time
and
> (ii) the use of method combinations is much more flexible than C++'s
(only)
> choice of "call the next method".
>
> faa
> "Jochen Schmidt" <···@dataheaven.de> wrote in message
> ···················@ID-22205.news.cis.dfn.de...
> > An old question I never dared to ask...
> >
> > I know multimethods have a lot of further features but the most stated
> > difference to single-methods is that multimethods specialize an all of
its
> > arguments.
> > But where is the difference at this point to e.g. some overloaded global
> > C++ functions?
> >
> > e.g.:
> >
> > #include <iostream.h>
> >
> > class A {};
> > class B {};
> > class C : public A {};
> >
> > void foo(A a, A b) { cout << "(A A)" << endl;}
> > void foo(B a, B b) { cout << "(B B)" << endl;}
> > void foo(A a, B b) { cout << "(A B)" << endl;}
> > void foo(B a, A b) { cout << "(B A)" << endl;}
> > //void foo(C a, B b) { cout << "(C B)" << endl;}
> >
> > int main()
> > {
> >   A a;
> >   B b;
> >   C c;
> >
> >   foo(a,a);
> >   foo(b,b);
> >   foo(a,b);
> >   foo(b,a);
> >   foo(c,b);
> >
> >   return 0;
> > }
> >
> >
> > This is similar to the most stated behavior of multimethods - but that
> > cannot be the whole game can it?
> >
> > Note: I'm not arguing that C++'s  global functions are better/equal to
CL
> > generic-functions but that this behavior of CL-Generic functions is the
> > first example I ever see if someone gives an explanation of what
> > multimethods are.
> >
> > confused...
> > Jochen Schmidt
> > ···@dataheaven.de
> >
> >
> > --
> >
>
>
From: Rainer Joswig
Subject: Re: Multimethods
Date: 
Message-ID: <joswig-B71EF4.01401629082000@news.is-europe.net>
In article <··············@ID-22205.news.cis.dfn.de>, Jochen Schmidt 
<···@dataheaven.de> wrote:
> I know multimethods have a lot of further features but the most stated
> difference to single-methods is that multimethods specialize an all of its 
> arguments.
> But where is the difference at this point to e.g. some overloaded global
> C++ functions?

AFAIK, C++ determines the "method" statically at compile time.
C++ does not have dynamic multi-method dispatching at run-time.

Common Lisp has.

-- 
Rainer Joswig, Hamburg, Germany
Email: ·············@corporate-world.lisp.de
Web: http://corporate-world.lisp.de/
From: Scott Ribe
Subject: Re: Multimethods
Date: 
Message-ID: <39ABCF17.ABCA49B6@miqs.com>
I like to point out that in C++ you have a choice:

- you can have run-time dispatch
- you can have multiple dispatch

You just can't have both! This is entirely consistent with C++ (and many
other languages): you have multiple special-purpose constructs, but the
more general construct that would subsume and surpass them is left
out--usually for the convenience of the compiler writers.

Rainer Joswig wrote:
> 
> In article <··············@ID-22205.news.cis.dfn.de>, Jochen Schmidt
> <···@dataheaven.de> wrote:
> > I know multimethods have a lot of further features but the most stated
> > difference to single-methods is that multimethods specialize an all of its
> > arguments.
> > But where is the difference at this point to e.g. some overloaded global
> > C++ functions?
> 
> AFAIK, C++ determines the "method" statically at compile time.
> C++ does not have dynamic multi-method dispatching at run-time.
> 
> Common Lisp has.
> 
> --
> Rainer Joswig, Hamburg, Germany
> Email: ·············@corporate-world.lisp.de
> Web: http://corporate-world.lisp.de/
From: Marco Antoniotti
Subject: Re: Multimethods
Date: 
Message-ID: <y6cem386o5y.fsf@octagon.mrl.nyu.edu>
Scott Ribe <·····@miqs.com> writes:

> I like to point out that in C++ you have a choice:
> 
> - you can have run-time dispatch
> - you can have multiple dispatch

What is the use of having 'multiple dispatch' if you can't do it at
run time?  If memory does not fail me, run-time dispatch on the first
argument has been the first enhancement introduced in C++ after its
first release. Cfr. the 'virtual' keyword.

> You just can't have both! This is entirely consistent with C++ (and many
> other languages): you have multiple special-purpose constructs, but the
> more general construct that would subsume and surpass them is left
> out--usually for the convenience of the compiler writers.

And to the discomfort of the actual programmer :)

Cheers

-- 
Marco Antoniotti =============================================================
NYU Bioinformatics Group			 tel. +1 - 212 - 998 3488
719 Broadway 12th Floor                          fax  +1 - 212 - 995 4122
New York, NY 10003, USA				 http://galt.mrl.nyu.edu/valis
From: Jochen Schmidt
Subject: Re: Multimethods
Date: 
Message-ID: <8ogulh$anpcg$1@ID-22205.news.cis.dfn.de>
Marco Antoniotti wrote:

> What is the use of having 'multiple dispatch' if you can't do it at
> run time?  If memory does not fail me, run-time dispatch on the first
> argument has been the first enhancement introduced in C++ after its
> first release. Cfr. the 'virtual' keyword.

The use is to write functions that specialize on more than one argument
and to make it possible to write n-ary functions that overload behavior of
inbuilt datatypes.

Sincerely yours,
Jochen Schmidt
From: Marco Antoniotti
Subject: Re: Multimethods
Date: 
Message-ID: <y6cn1hubzzr.fsf@octagon.mrl.nyu.edu>
Jochen Schmidt <···@dataheaven.de> writes:

> Marco Antoniotti wrote:
> 
> > What is the use of having 'multiple dispatch' if you can't do it at
> > run time?  If memory does not fail me, run-time dispatch on the first
> > argument has been the first enhancement introduced in C++ after its
> > first release. Cfr. the 'virtual' keyword.
> 
> The use is to write functions that specialize on more than one argument
> and to make it possible to write n-ary functions that overload behavior of
> inbuilt datatypes.

That is exactly why CLOS multiple dispatch is more useful to the
programmer, since it allows you to do things you simply can't in
single-dispatching OO languages like C++.

Cheers

-- 
Marco Antoniotti =============================================================
NYU Bioinformatics Group			 tel. +1 - 212 - 998 3488
719 Broadway 12th Floor                          fax  +1 - 212 - 995 4122
New York, NY 10003, USA				 http://galt.mrl.nyu.edu/valis
From: Lieven Marchand
Subject: Re: Multimethods
Date: 
Message-ID: <m3vgwkdp2m.fsf@localhost.localdomain>
Scott Ribe <·····@miqs.com> writes:

> You just can't have both! This is entirely consistent with C++ (and many
> other languages): you have multiple special-purpose constructs, but the
> more general construct that would subsume and surpass them is left
> out--usually for the convenience of the compiler writers.

You can accuse C++ of a lot of things, but being designed for the
convenience of the compiler writer certainly isn't one of them. I'd
rather write a CL compiler than a C++ one. 

C++ is the logical result of piecewise design by committee for a
community that is paranoid about introducing keywords (why break a
small fraction of existing programs in a completely detectable way if
we can add another meaning to static?), wants to stay compatible with
every mistake of the past and focuses on extremely local
optimizations. The whole mess is nicely described in Stroustrup's _The
design and evolution of C++_.

ObLisp: C++'s predecessor, C with Classes, had :before and :after
methods but they were removed in the transition to C++.


-- 
Lieven Marchand <···@bewoner.dma.be>
Lambda calculus - Call us a mad club
From: Scott Ribe
Subject: Re: Multimethods
Date: 
Message-ID: <39AD5ED3.748FB5CD@miqs.com>
Lieven Marchand wrote:
> 
> Scott Ribe <·····@miqs.com> writes:
> 
> You can accuse C++ of a lot of things, but being designed for the
> convenience of the compiler writer certainly isn't one of them. I'd
> rather write a CL compiler than a C++ one.

Yes, I muddled two different points into one paragraph.
From: Marius Vollmer
Subject: Re: Multimethods
Date: 
Message-ID: <87itsjaifb.fsf@zagadka.ping.de>
Rainer Joswig <······@corporate-world.lisp.de> writes:

> <···@dataheaven.de> wrote:
> >
> > But where is the difference at this point to e.g. some overloaded global
> > C++ functions?
> 
> AFAIK, C++ determines the "method" statically at compile time.

Right.  Effectively, the type of its arguments becomes part of the
name of a function, you just don't have to type it out explicitely
every time.  At times this can be mighty convenient, but it can also
become mighty confusing.
From: Kent M Pitman
Subject: Re: Multimethods
Date: 
Message-ID: <sfwhf85orzb.fsf@world.std.com>
Rainer Joswig <······@corporate-world.lisp.de> writes:

> In article <··············@ID-22205.news.cis.dfn.de>, Jochen Schmidt 
> <···@dataheaven.de> wrote:
> > I know multimethods have a lot of further features but the most stated
> > difference to single-methods is that multimethods specialize an all of its 
> > arguments.
> > But where is the difference at this point to e.g. some overloaded global
> > C++ functions?
> 
> AFAIK, C++ determines the "method" statically at compile time.
> C++ does not have dynamic multi-method dispatching at run-time.

Put another way, CL has the correct dispatching semantics.  C++ does not.

> Common Lisp has.

Right.

Also, of course, CL generic functions can have additional methods or new
definitions of already-existing methods loaded at runtime.
From: Clinton Hyde
Subject: Re: Multimethods
Date: 
Message-ID: <39B919DD.41667D3C@bbn.com>
Kent M Pitman wrote:

> Rainer Joswig <······@corporate-world.lisp.de> writes:
>
> > AFAIK, C++ determines the "method" statically at compile time.
> > C++ does not have dynamic multi-method dispatching at run-time.
>
> Put another way, CL has the correct dispatching semantics.  C++ does not.
>

and that led to the crappy "interface" approach in Java.

>
> > Common Lisp has.
>
> Right.
>
> Also, of course, CL generic functions can have additional methods or new
> definitions of already-existing methods loaded at runtime.

this is my primary gripe about Java...I needed to add a method for sorting a
vector, couldn't just define sort(vector v...) and load that. I had to coerce my
vector into an array, sort the array, then convert that back into my vector. ouch!

i.e., I want to add a new method to built-in classes occasionally, and I don't
want to do it by subclassing and using the subclass, because I can't guarantee
that any instance I come across is going to be my subclass. and I don't want to
have to get in the habit of needing system sources and rewrite that and include it
in my app--tain't safe.

 -- clint
From: Barry Margolin
Subject: Re: Multimethods
Date: 
Message-ID: <1pau5.63$7w2.1622@burlma1-snr2>
In article <·················@bbn.com>, Clinton Hyde  <·····@bbn.com> wrote:
>this is my primary gripe about Java...I needed to add a method for sorting a
>vector, couldn't just define sort(vector v...) and load that. I had to coerce my
>vector into an array, sort the array, then convert that back into my
>vector. ouch!

To be fair, this isn't really a Java-specific issue -- quite a few OO
languages have this limitation.  Many OO language designers believe in
strong encapsulation, where the class has a documented interface that can't
be changed without recompiling the class.  This is pretty much a necessity
if you want to do static, compile-time type checking -- these checks will
generally be based on that interface specification.

-- 
Barry Margolin, ······@genuity.net
Genuity, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: David Bakhash
Subject: Re: Multimethods
Date: 
Message-ID: <m3aedgcrjc.fsf@cadet.dsl.speakeasy.net>
Barry Margolin <······@genuity.net> writes:

> In article <·················@bbn.com>, Clinton Hyde <·····@bbn.com>
> wrote: >this is my primary gripe about Java...I needed to add a
> method for sorting a >vector, couldn't just define sort(vector v...)
> and load that. I had to coerce my >vector into an array, sort the
> array, then convert that back into my >vector. ouch!

> To be fair, this isn't really a Java-specific issue -- quite a few
> OO languages have this limitation.  Many OO language designers
> believe in strong encapsulation, where the class has a documented
> interface that can't be changed without recompiling the class.  This
> is pretty much a necessity if you want to do static, compile-time
> type checking -- these checks will generally be based on that
> interface specification.

I've seen the following (related) quote:

   "... it's just that in C++ and the like, you don't trust _anybody_,
   and in CLOS you basically trust everybody.  the practical result is
   that thieves and bums use C++ and nice people use CLOS."

dave
From: Jochen Schmidt
Subject: Re: Multimethods
Date: 
Message-ID: <8of85b$a19gd$1@ID-22205.news.cis.dfn.de>
Rainer Joswig wrote:

> In article <··············@ID-22205.news.cis.dfn.de>, Jochen Schmidt
> <···@dataheaven.de> wrote:
> > I know multimethods have a lot of further features but the most stated
> > difference to single-methods is that multimethods specialize an all of
> > its arguments.
> > But where is the difference at this point to e.g. some overloaded global
> > C++ functions?
> 
> AFAIK, C++ determines the "method" statically at compile time.
> C++ does not have dynamic multi-method dispatching at run-time.

Yes surely - as I said CL's generic functions/multimethods have much more 
features:

* definition/extension at runtime (as all in CL)
* method-combinations
* &optional, &key and &rest-parameters (as all lambda-lists in CL)
* eql-specializers

But the most common stated difference "MMs specialize on more than one
parameter" seems to be nothing special so far...

-- 
From: Craig Brozefsky
Subject: Re: Multimethods
Date: 
Message-ID: <87og2cbtxm.fsf@piracy.red-bean.com>
Jochen Schmidt <···@dataheaven.de> writes:

> Yes surely - as I said CL's generic functions/multimethods have much more 
> features:
> 
> * definition/extension at runtime (as all in CL)
> * method-combinations
> * &optional, &key and &rest-parameters (as all lambda-lists in CL)
> * eql-specializers
> 
> But the most common stated difference "MMs specialize on more than one
> parameter" seems to be nothing special so far...

Give yourself some time to break out of the habits and patterns other
languages without multi-dispatch engender, so that those situations
where multi-dispatch is useful will present themselves, instead of
being subconsciously avoided by the design principles you have
internalized from lesser languages.

A concrete example would be the interface between the database
independent, and DB drivers in UncommonSQL.  In that protocol there
are methods which dispatch on at least three arguments, use
eql-specializers, and method-combinations.

The job of interfacing to database drivers is something almost any
language can do regardless of wether it supports multi-dispatch or
not.  However in those languages, one would have a more complicated
API.  Even the ObjC systems which perform a similiar task are much
more complicated than the 20 function USQL protocol.

In practice I found that protocols which normally would require the
interaction of two or more subprotocols are easily replaced witha
single generic function using multi-dispatch.  This is because your
protocol can provide abstractions at the method lebvel for operations
that depend on the interactions of three or more objects.  Because of
this I found my object models being simpler, and the protocols
defining their interaction simpler, and easier to maintain as well.

-- 
Craig Brozefsky               <·····@red-bean.com>
Lisp Web Dev List  http://www.red-bean.com/lispweb
---  The only good lisper is a coding lisper.  ---
From: Jochen Schmidt
Subject: Re: Multimethods
Date: 
Message-ID: <8og66g$argra$1@ID-22205.news.cis.dfn.de>
Craig Brozefsky wrote:

> Jochen Schmidt <···@dataheaven.de> writes:
> 
> > Yes surely - as I said CL's generic functions/multimethods have much
> > more features:
> > 
> > * definition/extension at runtime (as all in CL)
> > * method-combinations
> > * &optional, &key and &rest-parameters (as all lambda-lists in CL)
> > * eql-specializers
> > 
> > But the most common stated difference "MMs specialize on more than one
> > parameter" seems to be nothing special so far...
> 
> Give yourself some time to break out of the habits and patterns other
> languages without multi-dispatch engender, so that those situations
> where multi-dispatch is useful will present themselves, instead of
> being subconsciously avoided by the design principles you have
> internalized from lesser languages.

hm... you seem to have overlooked my "note" in the first post.
I'am _aware_ of the many features and advantages of Common Lisp generic  
functions/multiple dispatch. I think I've clearly spoken out that I'm _not_ 
a C++ evangelist (God beware!).
Yes I've many years of experience in C++ but should I feel ashame of that?
Should I regret that I don't have learned Common Lisp as my first language?

Without any persuasion from any person I was convinced solely by the 
superior features of Common Lisp within days (!!!).

But to the point:

As I surely mentioned clear enough now that I don't want to "prove" that I 
can do the same in C++ as in Common Lisp but I wanted to get a really good 
example on the superiority of Common Lisps MMs against my example in C++.

When you take a look in my third post, I've found that easy little example 
that shows that fact. The lack of polymorphic behavior in c++ when using
global functions for something like multiple dispatch rules out the use of 
C++ in this point.

Sincerely yours,
Jochen Schmidt
From: Craig Brozefsky
Subject: Re: Multimethods
Date: 
Message-ID: <87r978vznn.fsf@piracy.red-bean.com>
Jochen Schmidt <···@dataheaven.de> writes:

> > Give yourself some time to break out of the habits and patterns other
> > languages without multi-dispatch engender, so that those situations
> > where multi-dispatch is useful will present themselves, instead of
> > being subconsciously avoided by the design principles you have
> > internalized from lesser languages.
> 
> hm... you seem to have overlooked my "note" in the first post.  I'am
> _aware_ of the many features and advantages of Common Lisp generic
> functions/multiple dispatch. I think I've clearly spoken out that
> I'm _not_ a C++ evangelist (God beware!).  Yes I've many years of
> experience in C++ but should I feel ashame of that?  Should I regret
> that I don't have learned Common Lisp as my first language?

My comment was not intended to paint you as an advocate of anything,
or to chastise you for knowing C++.  

The way I was reading your post, you understood the differences
between CL and other languages, and regarded them as advantages, but
had not had any situation where multi-dispatch proved to be a
significant advantage.  Having been thru a similiar situation,
although my original OO languages were Objective-C and Java, I
attempted to describe the process by which I came to find
multi-dispatch practically useful.

--
Craig Brozefsky               <·····@red-bean.com>
Lisp Web Dev List  http://www.red-bean.com/lispweb
---  The only good lisper is a coding lisper.  ---
From: David Hanley
Subject: Re: Multimethods
Date: 
Message-ID: <39ABD328.5D7E2CEF@ncgr.org>
Jochen Schmidt wrote:

> Rainer Joswig wrote:
>
> > In article <··············@ID-22205.news.cis.dfn.de>, Jochen Schmidt
> > <···@dataheaven.de> wrote:
> > > I know multimethods have a lot of further features but the most stated
> > > difference to single-methods is that multimethods specialize an all of
> > > its arguments.
> > > But where is the difference at this point to e.g. some overloaded global
> > > C++ functions?
> >
> > AFAIK, C++ determines the "method" statically at compile time.
> > C++ does not have dynamic multi-method dispatching at run-time.
>
> Yes surely - as I said CL's generic functions/multimethods have much more
> features:
>
> * definition/extension at runtime (as all in CL)
> * method-combinations
> * &optional, &key and &rest-parameters (as all lambda-lists in CL)
> * eql-specializers
>
> But the most common stated difference "MMs specialize on more than one
> parameter" seems to be nothing special so far...

"specialization" infers "dynamic specialization."  If, in your example, A,B,and
C
were derived from type X, and all the variable handles were type X, it would
still work as before in LISP.

This is important, because the whole point of writing generic code is that you
want to be able to do generic things to generic objects--and you can't do that
with C++ "multimethods."  The type's got to be there specifically.

dave
From: Kent M Pitman
Subject: Re: Multimethods
Date: 
Message-ID: <sfw3djo3da0.fsf@world.std.com>
Jochen Schmidt <···@dataheaven.de> writes:

> But the most common stated difference "MMs specialize on more than one
> parameter" seems to be nothing special so far...

Well, in some ways.  But, by the way, another thing not mentioned before
in the "sample C implementation" against which this was being compared is
that CLOS methods are detached from the issue of representation.  That is,
they don't mind being attached to the analog of "sealed" or "final" classes
since they do not reside "within" the class nor are they accessing any
information about how the class is represented.  So you can write methods
on primitive objects like integers and floats.
From: Jochen Schmidt
Subject: Re: Multimethods
Date: 
Message-ID: <8og6k9$ak9iu$1@ID-22205.news.cis.dfn.de>
Kent M Pitman wrote:

> Jochen Schmidt <···@dataheaven.de> writes:
> 
> > But the most common stated difference "MMs specialize on more than one
> > parameter" seems to be nothing special so far...
> 
> Well, in some ways.  But, by the way, another thing not mentioned before
> in the "sample C implementation" against which this was being compared is
> that CLOS methods are detached from the issue of representation.  That is,
> they don't mind being attached to the analog of "sealed" or "final"
> classes since they do not reside "within" the class nor are they accessing
> any
> information about how the class is represented.  So you can write methods
> on primitive objects like integers and floats.
> 

But that was the reason why I used global functions and not C++ class 
methods.
By the use of global functions in C++ we are able to define funtions that 
specialize on inbuilt types. It's the _only_ way how we can define a binary 
function with two arguments of inbuilt types!!!!.

But for the real reason why CLs MMs are superior to my little sample see my 
other post. (Lack of polymorphic behavior when using global functions)

Sincerely yours,
Jochen Schmidt

-- 
From: Marco Antoniotti
Subject: Re: Multimethods
Date: 
Message-ID: <y6cn1hw6om9.fsf@octagon.mrl.nyu.edu>
Jochen Schmidt <···@dataheaven.de> writes:

> Kent M Pitman wrote:
> 
> > Jochen Schmidt <···@dataheaven.de> writes:
> > 
> > > But the most common stated difference "MMs specialize on more than one
> > > parameter" seems to be nothing special so far...
> > 
> > Well, in some ways.  But, by the way, another thing not mentioned before
> > in the "sample C implementation" against which this was being compared is
> > that CLOS methods are detached from the issue of representation.  That is,
> > they don't mind being attached to the analog of "sealed" or "final"
> > classes since they do not reside "within" the class nor are they accessing
> > any
> > information about how the class is represented.  So you can write methods
> > on primitive objects like integers and floats.
> > 
> 
> But that was the reason why I used global functions and not C++ class 
> methods.
> By the use of global functions in C++ we are able to define funtions that 
> specialize on inbuilt types. It's the _only_ way how we can define a binary 
> function with two arguments of inbuilt types!!!!.
> 
> But for the real reason why CLs MMs are superior to my little sample see my 
> other post. (Lack of polymorphic behavior when using global functions)
> 
==============================================================================
#include <iostream.h>

class A
{
public:
  void message()
  {
    cout << "I am an A." << endl;
  }
};

class B
{
public:
  void message()
  {
    cout << "I am a B." << endl;
  }
};

class A1 : public A
{
public:
  void message()
  {
    cout << "I am an A1: you die if you call me." << endl;
    exit(1);
  }
};

class A2 : public A1
{
public:
  void message()
  {
    cout << "I am an A2 and I am much nicer that any A1." << endl;
  }
};

void I_cannot_do_what_CLOS_does(B *b, A1 *a)
{
  b->message();
  a->message();
}

int
main()
{
  A2* a = new A2();
  B* b = new B();

  I_cannot_do_what_CLOS_does(b, a);
}

[·······@tapulon C-stuff]$ g++ mm.C
[·······@tapulon C-stuff]$ ./a.out
I am a B.
I am an A1: you die if you call me.


The same program written in CLOS works as advertised.

Cheers

-- 
Marco Antoniotti =============================================================
NYU Bioinformatics Group			 tel. +1 - 212 - 998 3488
719 Broadway 12th Floor                          fax  +1 - 212 - 995 4122
New York, NY 10003, USA				 http://galt.mrl.nyu.edu/valis
From: Ray Blaak
Subject: Re: Multimethods
Date: 
Message-ID: <u8zteelsm.fsf@infomatch.com>
Marco Antoniotti <·······@cs.nyu.edu> writes:
> void I_cannot_do_what_CLOS_does(B *b, A1 *a)
> {
>   b->message();
>   a->message();
> }
>
> main()
> {
>   A2* a = new A2();
>   B* b = new B();
> 
>   I_cannot_do_what_CLOS_does(b, a);
> }
> 
> [·······@tapulon C-stuff]$ g++ mm.C
> [·······@tapulon C-stuff]$ ./a.out
> I am a B.
> I am an A1: you die if you call me.
> 
> The same program written in CLOS works as advertised.

Change "void message" to be "virtual void message", and C++ will also work as
advertised. Dispatching in C++ does not occur until the programmer explicitly
says something is dispatchable.

What C++ cannot do in a dispatching manner is have different versions of
I_cannot_do_what_CLOS_does. Overloaded ones that are determined at compile
time, yes, but not this:

void I_cannot_do_what_CLOS_does(B* b, A1* a)
{
  cout << "I got a B and an A1" << endl;
}

void I_cannot_do_what_CLOS_does(B* b, A2* a)
{
  cout << "I got a B and an A2" << endl;
}

void Doit(B* b, A1* a)
{
  // Only the first version is called. Multi-dispatching would allow the
  // second to be called if a was actually an A2.
  I_cannot_do_what_CLOS_does(b, a);
}

main()
{
  A1* a1 = new A1;
  A2* a2 = new A2;
  B* b = new B;

  Doit(b, a1);
  Doit(b, a2);
}

-- 
Cheers,                                        The Rhythm is around me,
                                               The Rhythm has control.
Ray Blaak                                      The Rhythm is inside me,
·····@infomatch.com                            The Rhythm has my soul.
From: Marco Antoniotti
Subject: Re: Multimethods
Date: 
Message-ID: <y6czolu62vq.fsf@octagon.mrl.nyu.edu>
Ray Blaak <·····@infomatch.com> writes:

> Marco Antoniotti <·······@cs.nyu.edu> writes:
> > void I_cannot_do_what_CLOS_does(B *b, A1 *a)
> > {
> >   b->message();
> >   a->message();
> > }
> >
> > main()
> > {
> >   A2* a = new A2();
> >   B* b = new B();
> > 
> >   I_cannot_do_what_CLOS_does(b, a);
> > }
> > 
> > [·······@tapulon C-stuff]$ g++ mm.C
> > [·······@tapulon C-stuff]$ ./a.out
> > I am a B.
> > I am an A1: you die if you call me.
> > 
> > The same program written in CLOS works as advertised.
> 
> Change "void message" to be "virtual void message", and C++ will also work as
> advertised. Dispatching in C++ does not occur until the programmer explicitly
> says something is dispatchable.

Of course, you are right.  As usual.  I should refrain from writing
things too hastily. :{  I stand corrected.

Cheers

-- 
Marco Antoniotti =============================================================
NYU Bioinformatics Group			 tel. +1 - 212 - 998 3488
719 Broadway 12th Floor                          fax  +1 - 212 - 995 4122
New York, NY 10003, USA				 http://galt.mrl.nyu.edu/valis
From: Rainer Joswig
Subject: Re: Multimethods
Date: 
Message-ID: <joswig-4003F3.06462529082000@news.is-europe.net>
In article <··············@ID-22205.news.cis.dfn.de>, Jochen Schmidt 
<···@dataheaven.de> wrote:

> Rainer Joswig wrote:
> 
> > In article <··············@ID-22205.news.cis.dfn.de>, Jochen Schmidt
> > <···@dataheaven.de> wrote:
> > > I know multimethods have a lot of further features but the most stated
> > > difference to single-methods is that multimethods specialize an all of
> > > its arguments.
> > > But where is the difference at this point to e.g. some overloaded global
> > > C++ functions?
> > 
> > AFAIK, C++ determines the "method" statically at compile time.
> > C++ does not have dynamic multi-method dispatching at run-time.

...

> But the most common stated difference "MMs specialize on more than one
> parameter" seems to be nothing special so far...

As I said, C++ determines it statically at compile time using
the declared types. So at runtime there is no dispatching
(hence no OO).

Bjarne Stroustrup discusses these issues in his book
"Design and Evolution of C++".

-- 
Rainer Joswig, Hamburg, Germany
Email: ·············@corporate-world.lisp.de
Web: http://corporate-world.lisp.de/
From: Jochen Schmidt
Subject: Re: Multimethods
Date: 
Message-ID: <8og6qb$ahkv0$1@ID-22205.news.cis.dfn.de>
Rainer Joswig wrote:


> > But the most common stated difference "MMs specialize on more than one
> > parameter" seems to be nothing special so far...
> 
> As I said, C++ determines it statically at compile time using
> the declared types. So at runtime there is no dispatching
> (hence no OO).
> 
> Bjarne Stroustrup discusses these issues in his book
> "Design and Evolution of C++".

Yes I realized that, but it is not the proper argument if I want to show a 
C++ person the fact that multiple-dispatch is _not_ the same as using
global functions in C++!
The lack of polymorphic behavior as I mentioned in he other mails is IMHO 
the right argument against my exampe.

Sincerely yours,
Jochen Schmidt

> 

-- 
From: Thom Goodsell
Subject: Re: Multimethods
Date: 
Message-ID: <7vitskrkvt.fsf@shalott.cra.com>
Jochen Schmidt <···@dataheaven.de> writes:

> Rainer Joswig wrote:
> 
> 
> > > But the most common stated difference "MMs specialize on more than one
> > > parameter" seems to be nothing special so far...
> > 
> > As I said, C++ determines it statically at compile time using
> > the declared types. So at runtime there is no dispatching
> > (hence no OO).
> > 
> > Bjarne Stroustrup discusses these issues in his book
> > "Design and Evolution of C++".
> 
> Yes I realized that, but it is not the proper argument if I want to show a 
> C++ person the fact that multiple-dispatch is _not_ the same as using
> global functions in C++!
> The lack of polymorphic behavior as I mentioned in he other mails is IMHO 
> the right argument against my exampe.

Actually, Rainer is making the same point you are. Because the proper
function is determined statically at compile time, rather than
dynamically at run time, there is no polymorphism.

Thom

-- 
Scientist				···@cra.com
Charles River Analytics		(617) 491-3474 x574
Cambridge, MA, USA		http://www.cra.com/
From: Jon S Anthony
Subject: Re: Multimethods
Date: 
Message-ID: <39AC2E53.24CD@synquiry.com>
Jochen Schmidt wrote:

> The lack of polymorphic behavior as I mentioned in he other mails is IMHO
> the right argument against my exampe.

You're still mixed up a bit.  What you really mean is the _dynamic_
polymorphic
behavior.  The C++ technique is also known as overloading (which has
been pointed
out to be a static _compile_ time polymorphic resolution).

Overloading _is_ a form of polymorphism - it's just one that resolves
_once_
at compile time.  So, if you write a method call at some point with some
arguments and the arguments can be resolved at compile time then the
correct
overloaded "function" will be selected and a call to _this specific_
function
inserted in the code.

The MM will resolve dynamically at runtime.  Think of it this way: the
difference
and advantage is exactly the same as that between simple dispatch (of a
single
distinguished parameter as found in most OOL) and overloading the same
function
name with a single parameter of different types which is resolved at
compile time.
MM "just" lets you have this advantage when you want to resolve over
several
parameters of varying types.


/Jon

-- 
Jon Anthony
Synquiry Technologies, Ltd. Belmont, MA 02478, 617.484.3383
"Nightmares - Ha!  The way my life's been going lately,
 Who'd notice?"  -- Londo Mollari
From: Jochen Schmidt
Subject: Re: Multimethods
Date: 
Message-ID: <8ohi71$arp7m$1@ID-22205.news.cis.dfn.de>
Jon S Anthony wrote:

> You're still mixed up a bit.  What you really mean is the _dynamic_
> polymorphic
> behavior.  The C++ technique is also known as overloading (which has
> been pointed
> out to be a static _compile_ time polymorphic resolution).

Hm do my postings get through the line.... I don't no!

As I mentioned earlier, I agree with Rainer that his statement is perfectly
true! 

But:

The problem was not to solve some things in C++ without
having the features of Lisp but to find a good example/explanation to show
a low-/midrange C++ programmer that there are points where it's language
misses features.
If I tell a low-/midrange C++ programmer about  a nice feature my favorite 
language Lisp has, I've to explain why this feature is:

1) _Really_ not available in his language (!!!!!)
   People will come with many many examples of how to do things and a lot   
   of them will be _much_ more advanced than my little example!
   So it is _important_ to give an example by using his knowledge!

2) Important for developing:
   Here is the place for defining new terms he doesn't know so far!
   After he has understood and accepted the lack of the feature in his     
   language the second problem is to show him that the feature is _really_
   important.

Yours sincerely
Jochen Schmidt
From: Johann Hibschman
Subject: Re: Multimethods
Date: 
Message-ID: <mtu2c3vcbz.fsf@astron.berkeley.edu>
Jochen Schmidt writes:

> The problem was not to solve some things in C++ without
> having the features of Lisp but to find a good example/explanation to show
> a low-/midrange C++ programmer that there are points where it's language
> misses features.

Hm.  How about linear algebra, as a basic one?

You want different methods for

  (mul <vector> <vector>)
  (mul <matrix> <vector>)
  (mul <vector> <matrix>)
  (mul <matrix> <matrix>)

  (matrix-solve <matrix> <vector>)

Now, the basics here aren't hard, but if you have multiple kinds of
matrices (sparse matrices, diagonal matrices, symmetric matrices,
upper and lower triangular, unitary, hermitian, etc.), suddenly it's
quite tricky.

Ideally, mul should look at the types of each argument and dispatch to
the optimal routine, using the inheritance graph information to
decide.  C++ overloading can't do this, since that only operates at
run-time.  C++ virtual methods won't work, because that only allows
dispatching on the first argument (effectively), not the second.

i.e. say
  (mul <upper-triangular-matrix> <lower-triangular-matrix>)
should call a special routine, different from
  (mul <upper-triangular-matrix> <generic-matrix>)
or
  (mul <generic-matrix> <lower-triangular-matrix>).

How would you do that in C++?

--J

-- 
Johann Hibschman                           ······@physics.berkeley.edu
From: Johann Hibschman
Subject: Re: Multimethods
Date: 
Message-ID: <mtem36ljup.fsf@astron.berkeley.edu>
Johann Hibschman writes:
> decide.  C++ overloading can't do this, since that only operates at
> run-time.  C++ virtual methods won't work, because that only allows
  ^^^^^^^^

Here, of course, I meant "compile-time".


-- 
Johann Hibschman                           ······@physics.berkeley.edu
From: Boris Schaefer
Subject: Re: Multimethods
Date: 
Message-ID: <874s42v9lt.fsf@qiwi.uncommon-sense.net>
Johann Hibschman <······@physics.berkeley.edu> writes:

| i.e. say
|   (mul <upper-triangular-matrix> <lower-triangular-matrix>)
| should call a special routine, different from
|   (mul <upper-triangular-matrix> <generic-matrix>)
| or
|   (mul <generic-matrix> <lower-triangular-matrix>).
| 
| How would you do that in C++?

C++ programmers solve this with templates, in particular, specializing
templates.  But then again, if you do this, you'll have to deal with
the most baroque syntax ever, compile times that should be measured in
centuries, and compiler warnings that only the illiterate might think
are legible.

Something like:

  class generic_matrix {};
  class lower_triangular_matrix : public generic_matrix {};
  class upper_triangular_matrix : public generic_matrix {};

  template<class result_type,
           class matrixA_type,
           class matrixB_type>
  result_type mul(matrixA_type& a, matrixB_type& b)
  {
    // do something
  }

  template<>
  generic_matrix mul(generic_matrix& a,
                     lower_triangular_matrix& b)
  {
    // do something else
  }

  template <>
  generic_matrix mul(upper_triangular_matrix a&,
                     lower_triangular_matrix b&)
  {
    // do something else
  }

Apart from the fact that I'm not sure I got the syntax right, this is
just plain evil, because the following will not dispatch correctly:

  generic_matrix foo (generic_matrix& a, generic_matrix& b)
  {
    return mul(a, b);
  }

  int main()
  {
    upper_triangular_matrix a;
    lower_triangular_matrix b;
    foo(a, b);  // will call `mul(matrixA_type&, matrixB_type&)'
  }

whereas the following would work:

  template<class result_type,
           class matrixA_type,
           class matrixB_type>
  result_type foo(matrixA_type a, matrixB_type b)
  {
    return mul(a, b);
  }

So, in effect either you templatize all your functions or, you loose
your polymorphism, which I think was the point of all this.

Well, nobody said C++ was a good language,
Boris

-- 
·····@uncommon-sense.net - <http://www.uncommon-sense.net/>

Beam me up, Scotty, there's no intelligent life down here!
From: George Neuner
Subject: Re: Multimethods
Date: 
Message-ID: <39ad624d.783569954@helice>
On 29 Aug 2000 17:09:52 -0700, Johann Hibschman
<······@physics.berkeley.edu> wrote:

>Jochen Schmidt writes:
>
>> The problem was not to solve some things in C++ without
>> having the features of Lisp but to find a good example/explanation to show
>> a low-/midrange C++ programmer that there are points where it's language
>> misses features.
>
>Hm.  How about linear algebra, as a basic one?
>
>You want different methods for
>
>  (mul <vector> <vector>)
>  (mul <matrix> <vector>)
>  (mul <vector> <matrix>)
>  (mul <matrix> <matrix>)
>
>  (matrix-solve <matrix> <vector>)
>
>Now, the basics here aren't hard, but if you have multiple kinds of
>matrices (sparse matrices, diagonal matrices, symmetric matrices,
>upper and lower triangular, unitary, hermitian, etc.), suddenly it's
>quite tricky.
>
>Ideally, mul should look at the types of each argument and dispatch to
>the optimal routine, using the inheritance graph information to
>decide.  C++ overloading can't do this, since that only operates at
>run-time.  C++ virtual methods won't work, because that only allows
>dispatching on the first argument (effectively), not the second.
>
>i.e. say
>  (mul <upper-triangular-matrix> <lower-triangular-matrix>)
>should call a special routine, different from
>  (mul <upper-triangular-matrix> <generic-matrix>)
>or
>  (mul <generic-matrix> <lower-triangular-matrix>).
>
>How would you do that in C++?
>

First you stop trying to think in Lisp  ;^)


Vectors are easy.  You create a general matrix base class with a
virtual function "mul" that takes a vector parameter.  You then just
override the function in any subclass that requires special handling.
[If you want to include different types of vectors - then the answer
is the same as for matrices (sp?) below.]

To handle the matrix variants, you first define your matrix base class
with a comprehensive set of virtual accessor functions so that you can
determine which elements exist and access their values.  Then you
write your virtual "mul" function to take a parameter of the base
matrix class and code the function in terms of the accessors.  Both
the accessors and the "mul" function must be overridden as necessary
in the matrix subclasses.

Its horribly convoluted [relative to Lisp], but it works.


George
From: Ray Blaak
Subject: Re: Multimethods
Date: 
Message-ID: <m366ohdh66.fsf@ns44.infomatch.bc.ca>
·······@dyn.SPAMMERS.DIE.com (George Neuner) writes:
> On 29 Aug 2000 17:09:52 -0700, Johann Hibschman
> <······@physics.berkeley.edu> wrote:
> >Hm.  How about linear algebra, as a basic one?
[...]
> >i.e. say
> >  (mul <upper-triangular-matrix> <lower-triangular-matrix>)
> >should call a special routine, different from
> >  (mul <upper-triangular-matrix> <generic-matrix>)
> >or
> >  (mul <generic-matrix> <lower-triangular-matrix>).
> >
> >How would you do that in C++?
[...]
> To handle the matrix variants, you first define your matrix base class
> with a comprehensive set of virtual accessor functions so that you can
> determine which elements exist and access their values.  Then you
> write your virtual "mul" function to take a parameter of the base
> matrix class and code the function in terms of the accessors.  Both
> the accessors and the "mul" function must be overridden as necessary
> in the matrix subclasses.


This would work, but it prevents one from doing all of the different and more
efficient algorithms for specialized matrix combinations. E.g. If you override
mul for UpperMatrix, you only get a "upper * generic" algorithm, but 
not "upper * lower".

Still, the general principle is right -- in C++ you have fake multi-dispatching
by doing "double" dispatching.

Here is my cut at it. Note how all the matrix classes know about each other,
but that's ok in this situation, since they are really interlated
anyway. Ignore also the fact that I put all the routine bodies in the class
declarations. To get this to actually compile I would need to put them in the
.cpp file, due to the mutual dependencies:


class UpperMatrix;
class LowerMatrix;

class Matrix
{
  virtual Matrix mul(Matrix& m)
    { return m.mul_by_Generic(this);
    }
  virtual Matrix mul_by_Generic(Matrix& m)
    { // generic m * generic this
    }
  virtual Matrix mul_by_Upper(UpperMatrix& m)
    { // upper m * generic this
    }
  virtual Matrix mul_by_Lower(LowerMatrix& m)
    { // lower m * generic this
    }
};

class UpperMatrix
{
  virtual Matrix mul(Matrix& m)
    { return m.mul_by_Upper(this);
    }
  virtual Matrix mul_by_Generic(Matrix& m)
    { // generic m * upper this
    }
  virtual Matrix mul_by_Upper(UpperMatrix& m)
    { // upper m * upper this
    }
  virtual Matrix mul_by_Lower(LowerMatrix& m)
    { // lower m * upper this
    }
};

class LowerMatrix
{
  virtual Matrix mul(Matrix& m)
    { return m.mul_by_Lower(this);
    }
  virtual Matrix mul_by_Generic(Matrix& m)
    { // generic m * lower this
    }
  virtual Matrix mul_by_Upper(UpperMatrix& m)
    { // upper m * lower this
    }
  virtual Matrix mul_by_Lower(LowerMatrix& m)
    { // lower m * lower this
    }
};

etc for the other matrices (only n^2+n routines to write for the n kinds!).

Now we can do:

  Matrix m;
  UpperMatrix u;
  LowerMatrix l;
  Matrix r;

  r = u.mul(m); // U::mul -> M::mul_by_Upper -> upper u * generic m
  r = u.mul(l); // U::mul -> L::mul_by_Upper -> upper u * lower l
  r = u.mul(u); // U::mul -> U::mul_by_Upper -> upper u * upper u
  r = m.mul(l); // M::mul -> L::mul_by_Generic -> generic m * lower l

It works, is completely dynamic over the matrix classes, and it is even
efficient, but it is more than a little tedious to set up.

-- 
Cheers,                                        The Rhythm is around me,
                                               The Rhythm has control.
Ray Blaak                                      The Rhythm is inside me,
·····@infomatch.com                            The Rhythm has my soul.
From: David Bakhash
Subject: Re: Multimethods
Date: 
Message-ID: <m3aedtok35.fsf@cadet.dsl.speakeasy.net>
Ray Blaak <·····@infomatch.com> writes:

> Still, the general principle is right -- in C++ you have fake
> multi-dispatching by doing "double" dispatching.

while this is a fine work-around, it's exactly that -- a work-around.
You can implement any of this stuff -- even in assembler.  That's not
the point.

> Here is my cut at it. Note how all the matrix classes know about
> each other, but that's ok in this situation, since they are really
> interlated anyway.

I do not share this opinion -- especially after glancing over the
code.  everything knowing about everything else is probably the worst
thing you could ever want.

If you consider an intricate class hierarchy with multiple
inheritance, then you realize that there is a right inheritance
structure that leads to most code reuse, and that is most logical for
understanding.  I think that matrix multiplication, being
non-commutative but associative, is probably one of the best examples
of when CL's object model is the biggest win.

before/after/around methods also make CLOS programming particularly
powerful, and simplify most method dispatch schemes from the
perspective of the programmer.

What I don't like about CLOS is a necessary evil.  I think it was KMP
who recently wrote about the benefits of not having the OO design all
lexically defined within the class definition, and the advantages.  I
agree completely, but the downside is that there's much less of a
protocol to stick to when programming, and so if you look at CLOS code
from different people, it all looks so amazingly different, and new
methods are defined all over the place for the same superclasses, and
they're just all over the place.  It can get hard to follow CLOS code
sometimes when there's a lot going on in different places.  I think
that in that sense, there's much more of a protocol in writing Java
code, and since its structure almost always looks the same, I can see
how people get comfortable with it really fast.

dave
From: Duane Rettig
Subject: Re: Multimethods
Date: 
Message-ID: <4em35qxsa.fsf@beta.franz.com>
David Bakhash <·····@alum.mit.edu> writes:

> What I don't like about CLOS is a necessary evil.  I think it was KMP
> who recently wrote about the benefits of not having the OO design all
> lexically defined within the class definition, and the advantages.  I
> agree completely, but the downside is that there's much less of a
> protocol to stick to when programming, and so if you look at CLOS code
> from different people, it all looks so amazingly different, and new
> methods are defined all over the place for the same superclasses, and
> they're just all over the place.  It can get hard to follow CLOS code
> sometimes when there's a lot going on in different places.  I think
> that in that sense, there's much more of a protocol in writing Java
> code, and since its structure almost always looks the same, I can see
> how people get comfortable with it really fast.

I don't find this to be the case.  When I look at CLOS code, I look in
a different place than you apparently do; I never start with trying to
grep through source.

If you have a CLOS that has the MOP or even just parts of it, you can
start with (clos:generic-function-methods #'<gf>) to get all of the
current methods for the function.  If you must see the source code,
you can then use whatever source-file-recording mechanism your lisp
provides to get you there.  Many times, though, I don't even want
to see the source code; the important issues are what the current
specializations are, what method(s) I want to trace, and what new
specializations I might want to add in order to get a new behavior,
even if only temporarily.

Starting a method search from the common ground, namely the generic
function, makes the arbitrary placement of method sources a non-issue.
In fact, using the MOP makes the presentation of the current CLOS
organization much tighter and more relevant than any language could
do with just source code organization.

-- 
Duane Rettig          Franz Inc.            http://www.franz.com/ (www)
1995 University Ave Suite 275  Berkeley, CA 94704
Phone: (510) 548-3600; FAX: (510) 548-8253   ·····@Franz.COM (internet)
From: David Bakhash
Subject: Re: Multimethods
Date: 
Message-ID: <m366ogeuou.fsf@cadet.dsl.speakeasy.net>
duane,

I agree with your line of thinking, and have made significant use of
OO browsing tools, e.g. with your product.  However, it's nice to be
able to read the code and know what's going on as well.  I think a
good editor, like Emacs, with (e)tags also makes things simpler, and
that has always been my savior.  The more I think about it, C++ and
Java arn't much better if better at all, in the case I mentioned.  I
think your arguments are valid here.  Anyway, I did say that I still
prefer the CLOS way overall, but it does open the door to a lot of
weird possible placements of code fragments.  Java, on the other hand, 
forces you into file-naming conventions, placement of certain methods
and classes, etc., that do make it easier in some cases to weave
through stuff.  I'm okay with Emacs and XEmacs, so I do okay
regardless.

dave
From: Chris Page
Subject: Re: Multimethods
Date: 
Message-ID: <B5D3F1BF.A183%page@best.NOSPAM.com>
in article ··············@cadet.dsl.speakeasy.net, David Bakhash at
·····@alum.mit.edu wrote on 2000.08.31 02:28:

> Ray Blaak <·····@infomatch.com> writes:
> 
>> Still, the general principle is right -- in C++ you have fake
>> multi-dispatching by doing "double" dispatching.
> 
> while this is a fine work-around, it's exactly that -- a work-around. You can
> implement any of this stuff -- even in assembler.  That's not the point.

Actually, I think it is exactly the point: That this sort of thing can be
done in C++, but it's terribly convoluted and burdensome. Thus, CL (or
Dylan, or ...) has an advantage here.

> What I don't like about CLOS is a necessary evil.  I think it was KMP who
> recently wrote about the benefits of not having the OO design all lexically
> defined within the class definition, and the advantages.  I agree completely,
> but the downside is that there's much less of a protocol to stick to when
> programming, and so if you look at CLOS code from different people, it all
> looks so amazingly different, and new methods are defined all over the place
> for the same superclasses, and they're just all over the place.  It can get
> hard to follow CLOS code sometimes when there's a lot going on in different
> places.  I think that in that sense, there's much more of a protocol in
> writing Java code, and since its structure almost always looks the same, I can
> see how people get comfortable with it really fast.

Yes, class definitions can provide a kind of interface documentation. On the
other hand, consider what I wrote in comp.lang.dylan:

---------------------8<---------------------
Message-ID: <··················@best.NOSPAM.com>
Date: Wed, 23 Aug 2000 10:32:08 -0700

Scott Meyers wrote an interesting C++ article:

  "How Non-Member Functions Improve Encapsulation"

  <http://www.cuj.com/archive/1802/feature.html>

Which I read as an argument for Dylan's style of object model, where:

- classes (ideally) only declare slot getter and setter functions

- other related functions are written in terms of slot getters/setters

- class names and related function names are placed in a common namespace
  to indicate their relatedness

He points out that encapsulation is increased because only the getters and
setters need to be rewritten if the slot implementations change, and this
type of change does not alter the "interface" of a class. Furthermore,
subsets of the interface can be placed in separate headers, minimizing
compilation dependencies and allowing for recombining them into
application-specific interfaces.

It felt like I was reading about Dylan modules.

It also made me smile when he acknowledged that the syntax for calling
non-member functions "member(foo)" is different from accessing members
directly "foo.member", because Dylan (in its all-knowing benevolent wisdom
:-) allows for the same syntax to be used for both, confirming their
semantic equivalence.

I'm glad to report that he says it is a trivial difference. He points out
that there are generally a number of non-member functions that operate on
classes: "If you reflect a bit and are honest with yourself, you'll admit
that you have this alleged inconsistency with all the nontrivial classes you
use, because no class has every function desired by every client. Every
client adds at least a few convenience functions of their own, and these
functions are always non-members."
[...]
---------------------8<---------------------

In other words, the complete interface for a class is never completely in
the class definition anyway. Namespaces (and documentation, of course)
provide higher-level ways to organize and describe interfaces.

-- 
Chris Page
Mac OS Guy
Palm, Inc.

let mail-to = concatenate( "Chris Page <page", ·@", "best.com>");
From: Ray Blaak
Subject: Re: Multimethods
Date: 
Message-ID: <m3lmxcu02y.fsf@blight.transcend.org>
David Bakhash <·····@alum.mit.edu> writes:
> Ray Blaak <·····@infomatch.com> writes:
> > Here is my cut at it. Note how all the matrix classes know about
> > each other, but that's ok in this situation, since they are really
> > interlated anyway.

[about a C++ "double" dispatch workaround for multi-dispatch:
 A.mul(B) -> B.mul_by_A(A) -> A * B specific algorithm]

> I do not share this opinion -- especially after glancing over the
> code.  everything knowing about everything else is probably the worst
> thing you could ever want.

I don't think the mutual dependency problem is so bad, actually. It can be
reduced a fair bit.

The various mul_by_* methods can be made protected so that they can only be
abused internally by the maxtrix classes. As previously suggested, virtual
element accessors can be used to minimize the exposure of the detailed matrix
data structure implementations. In the worst case, careful use of "friend"
control can be used to selectively expose only what is necessary among
particular sets of classes.

More importantly, however, multi-dispatch on a set of parameters means, by
definition, that there are specialized algorithms for specific
combinations. Such algorithms will have special knowledge of their particular
parameters, for otherwise one wouldn't be writing such a specific routine in
the first place.

I submit that multi-dispatching implies (some) detailed knowledge about the
parameters involved that crosses class boundaries, regardless of the language
used to implement it.

-- 
Cheers,                                        The Rhythm is around me,
                                               The Rhythm has control.
Ray Blaak                                      The Rhythm is inside me,
·····@infomatch.com                            The Rhythm has my soul.
From: Chris Page
Subject: Re: Multimethods
Date: 
Message-ID: <B5D3F6A1.A186%page@best.NOSPAM.com>
in article ··············@ns44.infomatch.bc.ca, Ray Blaak at
·····@infomatch.com wrote on 2000.08.31 00:27:

> Still, the general principle is right -- in C++ you have fake
> multi-dispatching by doing "double" dispatching.

It's important to remember that C++ supports RTTI (RunTime Type
Information), which allows for dynamic dispatching. This can make the
"double" dispatching a little simpler. Of course, you still have to write
your own dispatching code, but it can reduce the number of methods back to a
point where it looks more like multi-methods.

As a side note, I realized one day that templates and RTTI can be thought of
as quite similar. Templates provide static dispatching and RTTI provides
dynamic dispatching. Choosing one or the other can be simply a matter of
choosing to optimize code speed vs. code size. Of course, dynamic
dispatching requires explicit "if/then" tests in the code, but depending on
the situation, this could be easier to read and maintain than the equivalent
templates.

-- 
Chris Page
Mac OS Guy
Palm, Inc.

let mail-to = concatenate( "Chris Page <page", ·@", "best.com>");
From: Johan Kullstam
Subject: Re: Multimethods
Date: 
Message-ID: <m31yyxehv8.fsf@sysengr.res.ray.com>
Johann Hibschman <······@physics.berkeley.edu> writes:

> Jochen Schmidt writes:
> 
> > The problem was not to solve some things in C++ without
> > having the features of Lisp but to find a good example/explanation to show
> > a low-/midrange C++ programmer that there are points where it's language
> > misses features.
> 
> Hm.  How about linear algebra, as a basic one?
> 
> You want different methods for
> 
>   (mul <vector> <vector>)
>   (mul <matrix> <vector>)
>   (mul <vector> <matrix>)
>   (mul <matrix> <matrix>)
> 
>   (matrix-solve <matrix> <vector>)
> 
> Now, the basics here aren't hard, but if you have multiple kinds of
> matrices (sparse matrices, diagonal matrices, symmetric matrices,
> upper and lower triangular, unitary, hermitian, etc.), suddenly it's
> quite tricky.
> 
> Ideally, mul should look at the types of each argument and dispatch to
> the optimal routine, using the inheritance graph information to
> decide.  C++ overloading can't do this, since that only operates at
> run-time.  C++ virtual methods won't work, because that only allows
> dispatching on the first argument (effectively), not the second.
> 
> i.e. say
>   (mul <upper-triangular-matrix> <lower-triangular-matrix>)
> should call a special routine, different from
>   (mul <upper-triangular-matrix> <generic-matrix>)
> or
>   (mul <generic-matrix> <lower-triangular-matrix>).
> 
> How would you do that in C++?

i'd add a flags field to the matrix structure.  bits could set
upper-triagular, lower-triangular, symmetric, &c.

this way everything is a "matrix", but your run-time can distinguish
them by the flag setting.

matrix functions would do dispatch by hand in a switch, series of if
statements or a lookup into a vector of functions.

it's a bit tedious to code and perhaps not elegant, but i think it
would work.  the fact that it is the way a person would do it in plain
C doesn't matter.  C++ doesn't actually require using any of its fancy
features.  all you have to do is avoid the extra keywords.

-- 
J o h a n  K u l l s t a m
[········@ne.mediaone.net]
sysengr
From: Barry Margolin
Subject: Re: Multimethods
Date: 
Message-ID: <YAst5.42$_41.1616@burlma1-snr2>
In article <··············@sysengr.res.ray.com>,
Johan Kullstam  <········@ne.mediaone.net> wrote:
>Johann Hibschman <······@physics.berkeley.edu> writes:
>> How would you do that in C++?
>
>i'd add a flags field to the matrix structure.  bits could set
>upper-triagular, lower-triangular, symmetric, &c.
>
>this way everything is a "matrix", but your run-time can distinguish
>them by the flag setting.
>
>matrix functions would do dispatch by hand in a switch, series of if
>statements or a lookup into a vector of functions.

But that's not Object Oriented.  In order to add support for new types, you
would have to modify that switch statement.  One of the things that most
distinguishes OO from non-OO is that you can add new classes without having
to modify existing classes -- the OO dispatching engine takes care of it
automatically.

-- 
Barry Margolin, ······@genuity.net
Genuity, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Tim Bradshaw
Subject: Re: Multimethods
Date: 
Message-ID: <ey3hf7ty3kd.fsf@cley.com>
* Johan Kullstam wrote:

> it's a bit tedious to code and perhaps not elegant, but i think it
> would work.  the fact that it is the way a person would do it in plain
> C doesn't matter.  C++ doesn't actually require using any of its fancy
> features.  all you have to do is avoid the extra keywords.

`The best thing about C++ is that you can carry on writing C in it.'

--tim
From: Frank A. Adrian
Subject: Re: Multimethods
Date: 
Message-ID: <oFFt5.4739$Xq2.540340@news.uswest.net>
"Johan Kullstam" <········@ne.mediaone.net> wrote in message
···················@sysengr.res.ray.com...

> it's a bit tedious to code and perhaps not elegant, but i think it
> would work.  the fact that it is the way a person would do it in plain
> C doesn't matter.  C++ doesn't actually require using any of its fancy
> features.  all you have to do is avoid the extra keywords.

Yes, it would work, but the point is inherent in your quote: "it's a bit
tedious to code and perhaps not elegant".  When all is said and done, the
only difference between different Turing machine equivalent languages is the
ease with which they can aid you in communicating with the machine and other
developers what the system is supposed to do; otherwise, we'd all be
toggling in hex-bytes from a front-panel somewhere.  The statement that
"it's a bit tedious to code" is pretty damning unless balanced by some other
quality that makes the "tediousness" worthwhile.

faa

P.S.  If someone held a paycheck to my head and I had to do this in C++, I'd
probably use a set of templated algorithms.  It would not only be more
efficient than the dynamically checked code (see U Waterloo's Blitz project,
for example), but also much more clear.  However, that being said, this is
one place where multimethods provide a clear win over the double-dispatching
patterns that have to be used in C++, Smalltalk, etc., where methods are
dispatched only on the class of the first argument.
From: Jon S Anthony
Subject: Re: Multimethods
Date: 
Message-ID: <39AC5AC1.1336@synquiry.com>
Jochen Schmidt wrote:
> 
> Hm do my postings get through the line.... I don't no!

Possibly just usenet delivery timing issues...


> The problem was ... to find a good example/explanation to show

Well, you won't get anywhere much with one example. You will need
several examples which you can then attempt to point out the
generalization.

> 1) _Really_ not available in his language (!!!!!)

Frankly this is obvious from the previously given explanation:

> > The MM will resolve dynamically at runtime.  Think of it this way: the
> > difference and advantage is exactly the same as that between simple
> > dispatch (of a single distinguished parameter as found in most OOL)
> > and overloading the same function name with a single parameter of
> > different types which is resolved at compile time.  MM "just" lets you
> > have this advantage when you want to resolve over several parameters
> > of varying types <dynamically>.

If they don't understand or get this point, the case is hopeless.  It
describes the difference with analogy to what they (supposedly)
already know.  And the analogy is pretty exact (there isn't any
"impedance mismatch").


> 2) Important for developing:
> language the second problem is to show him that the feature is _really_
> important.

Either he will understand this from the general description or he will
be completely hung up on specifics.  If the latter, then getting this
will _only_ happen if he sees how this can help him in some problem
that he is actually facing.

Good luck...


/Jon

-- 
Jon Anthony
Synquiry Technologies, Ltd. Belmont, MA 02478, 617.484.3383
"Nightmares - Ha!  The way my life's been going lately,
 Who'd notice?"  -- Londo Mollari
From: Tim Bradshaw
Subject: Re: Multimethods
Date: 
Message-ID: <ey3aedwffi5.fsf@cley.com>
* Jochen Schmidt wrote:

> Yes I realized that, but it is not the proper argument if I want to show a 
> C++ person the fact that multiple-dispatch is _not_ the same as using
> global functions in C++!
> The lack of polymorphic behavior as I mentioned in he other mails is IMHO 
> the right argument against my exampe.

But the `polymorphic behaviour' you demonstrate is *because of*
runtime dispatching!  The C (or java) version prints the `wrong' thing
because it's dispatching on the declared type of the arguments at
compile time, the CL version prints the right thing because it
dispatches on the actual runtime type of the arguments.

--tim
From: Jochen Schmidt
Subject: Re: Multimethods
Date: 
Message-ID: <8oga8j$a1qsn$1@ID-22205.news.cis.dfn.de>
Tim Bradshaw wrote:

> * Jochen Schmidt wrote:
> 
> > Yes I realized that, but it is not the proper argument if I want to show
> > a C++ person the fact that multiple-dispatch is _not_ the same as using
> > global functions in C++!
> > The lack of polymorphic behavior as I mentioned in he other mails is
> > IMHO the right argument against my exampe.
> 
> But the `polymorphic behaviour' you demonstrate is *because of*
> runtime dispatching!  The C (or java) version prints the `wrong' thing
> because it's dispatching on the declared type of the arguments at
> compile time, the CL version prints the right thing because it
> dispatches on the actual runtime type of the arguments.

That's normal behavior in dynamic-typed systems!
It is true that this is possible because of the runtime dispatching 
facilities of Common Lisp but if you want to describe that fact to a C++-man
he will only look at you with big eyes, not understanding what you mean!
The example shows the interesting fact by using C++ terms and not CL-terms.
This is why I agreed with Rainer but have said that the example that Paul
Foley gaves me is _more_ what I'am searched for!

Sincerely yours,
Jochen Schmidt
From: David Bakhash
Subject: Re: Multimethods
Date: 
Message-ID: <m3wvh0e7wj.fsf@cadet.dsl.speakeasy.net>
Jochen Schmidt <···@dataheaven.de> writes:

> This is why I agreed with Rainer but have said that the example that
> Paul Foley gaves me is _more_ what I'am searched for!

where is this example?  I can't find it on Usenet.

dave
From: Jochen Schmidt
Subject: Re: Multimethods
Date: 
Message-ID: <8ogu40$b1nve$1@ID-22205.news.cis.dfn.de>
David Bakhash wrote:

> Jochen Schmidt <···@dataheaven.de> writes:
> 
> > This is why I agreed with Rainer but have said that the example that
> > Paul Foley gaves me is _more_ what I'am searched for!
> 
> where is this example?  I can't find it on Usenet.

Hm... I was sure I reposted it... but I cannot find it too this time so I 
will repost it here thanks:

As Paul Foley showed me per private mail there is a real difference:
By using the global-functions for simulating something similar like MMs
in CL we would lose polymorphy as following example shows:

#include <iostream.h>

class A {};
class B {};
class C : public A {};

void foo(A a, A b) { cout << "(A A)" << endl;}
void foo(B a, B b) { cout << "(B B)" << endl;}
void foo(A a, B b) { cout << "(A B)" << endl;}
void foo(B a, A b) { cout << "(B A)" << endl;}
void foo(C a, B b) { cout << "(C B)" << endl;}
void bar(A x, B y) { foo(x,y);}  // NEW

int main()
{
  A a;
  B b;
  C c;
  
  foo(a,a);
  foo(b,b);
  foo(a,b);
  foo(b,a);
  foo(c,b);
  bar(c,b);  // NEW

  return 0;
}

The call to bar() prints (A B) !!!
When using polymorphy in C++ we would have to use "virtual-methods", so 
we are restricted to single-dispatch.
Note: The parameters of virtual-methods suffer the same problem like in 
above example with global functions - so we indeed really have only SMs in 
C++.

Thanks for the help!

Yours sincerely
Jochen Schmidt

> 
> dave

-- 
From: Tim Bradshaw
Subject: Re: Multimethods
Date: 
Message-ID: <ey366okfall.fsf@cley.com>
* Jochen Schmidt wrote:
> It is true that this is possible because of the runtime dispatching 
> facilities of Common Lisp but if you want to describe that fact to a C++-man
> he will only look at you with big eyes, not understanding what you mean!
> The example shows the interesting fact by using C++ terms and not CL-terms.
> This is why I agreed with Rainer but have said that the example that Paul
> Foley gaves me is _more_ what I'am searched for!

I think this is a big mistake.  While it's true that C++ people will
often have a hard time understanding dynamism, it's such an important
aspect of the language that if you don't explain that this is what is
actually going on then you've kind of avoided answering the question.

Trying to explain Lisp/CLOS `in C++ terms' is like trying to explain
physics to someone who doesn't understand calculus: it just becomes a
series of rabbits which you pull out of a hat at appropriate moments,
and they'll end up getting annoyed at you because they can't see the
underlying thing which is going on and making it all possible.  

Once you've explained dynamism, then things like `runtime dispatching'
or `polymorphism' become obvious consequences, and you can see that
C++ is kind of like pre-gallilean physics where they have glimpses of
what is going on, but no overall picture at all, and a completely
bizarre cosmology to explain all the little fragments they can see.

Of course some people will refuse to understand calculus, or dynamic
typing, but `static typing people are *just too stupid*'[1].

--tim

[1] Does anyone have the exact quote from Richard Gabriel's talk last
    year?
From: Jochen Schmidt
Subject: Re: Multimethods
Date: 
Message-ID: <8ogtuk$ampcc$1@ID-22205.news.cis.dfn.de>
Tim Bradshaw wrote:

> * Jochen Schmidt wrote:
> > It is true that this is possible because of the runtime dispatching
> > facilities of Common Lisp but if you want to describe that fact to a
> > C++-man he will only look at you with big eyes, not understanding what
> > you mean! The example shows the interesting fact by using C++ terms and
> > not CL-terms. This is why I agreed with Rainer but have said that the
> > example that Paul Foley gaves me is _more_ what I'am searched for!
> 
> I think this is a big mistake.  While it's true that C++ people will
> often have a hard time understanding dynamism, it's such an important
> aspect of the language that if you don't explain that this is what is
> actually going on then you've kind of avoided answering the question.
> 
> Trying to explain Lisp/CLOS `in C++ terms' is like trying to explain
> physics to someone who doesn't understand calculus: it just becomes a
> series of rabbits which you pull out of a hat at appropriate moments,
> and they'll end up getting annoyed at you because they can't see the
> underlying thing which is going on and making it all possible.
> 
> Once you've explained dynamism, then things like `runtime dispatching'
> or `polymorphism' become obvious consequences, and you can see that
> C++ is kind of like pre-gallilean physics where they have glimpses of
> what is going on, but no overall picture at all, and a completely
> bizarre cosmology to explain all the little fragments they can see.
> 
> Of course some people will refuse to understand calculus, or dynamic
> typing, but `static typing people are *just too stupid*'[1].

I feel really really misunderstood today....
If I give a C++ guy an example in C++ terms (he fully understands) where 
C++ (!!!) lacks a certain feature (like multiple-dispatch) then I think 
it's good. If then the C++ guy asks how to do it better, then I can explain 
him how lisp it does in a "Lispy" way.

to make it short - yes you are right we cannot explain CLs features by 
examples using a language like C++! But that wasn't that what I've said!
My example should show the lack of multiple dispatch in _C++_

I hope it is not my bad english that makes it so difficult to understand 
me...

Sincerely yours,
Jochen Schmidt
From: Lieven Marchand
Subject: Re: Multimethods
Date: 
Message-ID: <m3u2c4doy9.fsf@localhost.localdomain>
Jochen Schmidt <···@dataheaven.de> writes:

> That's normal behavior in dynamic-typed systems!
> It is true that this is possible because of the runtime dispatching 
> facilities of Common Lisp but if you want to describe that fact to a C++-man
> he will only look at you with big eyes, not understanding what you mean!

Tell them it's a generalization of the Visitor pattern built in in the
language. The Visitor pattern provides you with dispatch on 2
arguments, at the cost of a fair amount of setup. Going beyond 2
arguments would become very messy.

-- 
Lieven Marchand <···@bewoner.dma.be>
Lambda calculus - Call us a mad club
From: Jochen Schmidt
Subject: Re: Multimethods
Date: 
Message-ID: <8oguc2$at1qk$1@ID-22205.news.cis.dfn.de>
Lieven Marchand wrote:

> Jochen Schmidt <···@dataheaven.de> writes:
> 
> > That's normal behavior in dynamic-typed systems!
> > It is true that this is possible because of the runtime dispatching
> > facilities of Common Lisp but if you want to describe that fact to a
> > C++-man he will only look at you with big eyes, not understanding what
> > you mean!
> 
> Tell them it's a generalization of the Visitor pattern built in in the
> language. The Visitor pattern provides you with dispatch on 2
> arguments, at the cost of a fair amount of setup. Going beyond 2
> arguments would become very messy.
> 

Yes true - the Visitor-pattern is a classical example where 
multiple-dispatch can save a lot of work. More than that - the 
Visitor-Pattern is only needed if we _have_ no multiple dispatch.

Good example! I should have thought of that!

Sincerely yours,
Jochen Schmidt
From: Paolo Amoroso
Subject: Re: Multimethods
Date: 
Message-ID: <3+SsOdrhe+zEofWGO9BiMrP5FcF0@4ax.com>
On Tue, 29 Aug 2000 20:14:01 +0000, Jochen Schmidt <···@dataheaven.de>
wrote:

> multiple-dispatch can save a lot of work. More than that - the 
> Visitor-Pattern is only needed if we _have_ no multiple dispatch.
> 
> Good example! I should have thought of that!

Visit Peter Norvig's Web site:

  http://www.norvig.com/

In the publications section look for the document "Design Patterns in
Dynamic Programming" (it's a PowerPoint presentation). You will find other
food for thought. Have (de)fun,


Paolo
-- 
EncyCMUCLopedia * Extensive collection of CMU Common Lisp documentation
http://cvs2.cons.org:8000/cmucl/doc/EncyCMUCLopedia/
From: Scott Ribe
Subject: Re: Multimethods
Date: 
Message-ID: <39AD5F10.1D197A24@miqs.com>
Jochen Schmidt wrote:
> 
> But the most common stated difference "MMs specialize on more than one
> parameter" seems to be nothing special so far...

The easiest way to point out the usefulness of MM is to note that with
it one does not need the "Visitor Pattern". If you are familiar with its
description in the patterns book, a few minutes' thought will be enough
for you to find that in CL it reduces to nothing more than a naming
convention, IOW a multimethod named for example "Visit" that dispatches
on both the "host" and "guest".
From: Jochen Schmidt
Subject: Re: Multimethods
Date: 
Message-ID: <8of9g8$ar53s$1@ID-22205.news.cis.dfn.de>
As Paul Foley showed me per private mail there is a real difference:
By using the global-functions for simulating something similar like MMs
in CL we would lose polymorphy as following example shows:

#include <iostream.h>

class A {};
class B {};
class C : public A {};

void foo(A a, A b) { cout << "(A A)" << endl;}
void foo(B a, B b) { cout << "(B B)" << endl;}
void foo(A a, B b) { cout << "(A B)" << endl;}
void foo(B a, A b) { cout << "(B A)" << endl;}
void foo(C a, B b) { cout << "(C B)" << endl;}
void bar(A x, B y) { foo(x,y);}  // NEW

int main()
{
  A a;
  B b;
  C c;
  
  foo(a,a);
  foo(b,b);
  foo(a,b);
  foo(b,a);
  foo(c,b);
  bar(c,b);  // NEW

  return 0;
}

The call to bar() prints (A B) !!!
When using polymorphy in C++ we would have to use "virtual-methods", so 
we are restricted to single-dispatch.
Note: The parameters of virtual-methods suffer the same problem like in 
above example with global functions - so we indeed really have only SMs in 
C++.

Thanks for the help!

Yours sincerely
Jochen Schmidt