Return Styles: Pseud0ch, Terminal, Valhalla, NES, Geocities, Blue Moon. Entire thread

multiple dispatch

Name: Anonymous 2012-01-21 4:10

Lisp:


[1]> (defclass B () ())
#<STANDARD-CLASS B>
[2]> (defclass C () ())
#<STANDARD-CLASS C>
[3]> (defgeneric f (x y))
#<STANDARD-GENERIC-FUNCTION F>
[4]> (defmethod f ((x B) (y B)) (print "BB"))
#<STANDARD-METHOD (#<STANDARD-CLASS B> #<STANDARD-CLASS B>)>
[5]> (defmethod f ((x B) (y C)) (print "BC"))
#<STANDARD-METHOD (#<STANDARD-CLASS B> #<STANDARD-CLASS C>)>
[6]> (defmethod f ((x C) (y B)) (print "CB"))
#<STANDARD-METHOD (#<STANDARD-CLASS C> #<STANDARD-CLASS B>)>
[7]> (defmethod f ((x C) (y C)) (print "CC"))
#<STANDARD-METHOD (#<STANDARD-CLASS C> #<STANDARD-CLASS C>)>
[8]> (f (make-instance 'B) (make-instance 'B))

"BB"
"BB"
[9]> (f (make-instance 'B) (make-instance 'C))

"BC"
"BC"
[10]> (f (make-instance 'C) (make-instance 'B))

"CB"
"CB"
[11]> (f (make-instance 'C) (make-instance 'C))

"CC"
"CC"
[12]>
Bye.


C++:


#include <iostream>

using namespace std;

struct A;
struct B;
struct C;

struct A {
  virtual ~A() {}

  virtual void f(A* y) = 0;

  virtual void f(B* y) = 0;
  virtual void f(C* y) = 0;

  virtual void g(B* y) = 0;
  virtual void g(C* y) = 0;
};

struct B : public A {
  void f(A* y);

  void f(B* y);
  void f(C* y);

  void g(B* y);
  void g(C* y);
};

struct C : public A {
  void f(A* y);

  void f(B* y);
  void f(C* y);

  void g(B* y);
  void g(C* y);
};

void B::f(A* y) { y->g(this); }

void B::f(B* y) { cout << "BB" << endl; }
void B::f(C* y) { cout << "BC" << endl; }

void B::g(B* y) { y->f(this); }
void B::g(C* y) { y->f(this); }


void C::f(A* y) { y->g(this); }

void C::f(B* y) { cout << "CB" << endl; }
void C::f(C* y) { cout << "CC" << endl; }

void C::g(B* y) { y->f(this); }
void C::g(C* y) { y->f(this); }

int main(int argc, char** argv) {
  A* b = new B();
  A* c = new C();
  b->f(b);
  b->f(c);
  c->f(b);
  c->f(c);
  delete b;
  delete c;
  return 0;


$ g++ gen.cpp
$ a.out
BB
BC
CB
CC

Name: Anonymous 2012-01-22 15:04

>>42

no, that is multiple dispatch. In the main function, the compiler only sees that a and b are of type generic_p, and then f is called on them. Based upon what the types of a and b are at runtime, f will call a different function. It's true that in this example, the compiler could infer that a will point to memory allocated and initialized for a struct A, and b points to memory allocated and initialized for a struct B, but this technique can scale to cases where the compiler wont be able to make such an optimization.

It's true that inheritance is a bitch using this method, but it can be done by managing the switch tables, or generating them from a description of the inheritance hierarchy.

And using a switch statement off of a type flag is one way to get the same functionality obtained with virtual methods. In fact, this is probably the most popular method of getting dynamic dispatch in seeples.

passing around function pointers is probably the most general form for polymorphism, but it isn't always very convenient, or manageable.

Newer Posts
Don't change these.
Name: Email:
Entire Thread Thread List