Dan Sugalski <[EMAIL PROTECTED]> wrote:

> Now, there is one big gotcha here -- multimethod dispatch. I'm not
> entirely sure that we can do this properly and still give classes
> full control over how methods are looked for and where they go.

Thinking about MMD a bit more, I can imagine the following scheme:

0) Our current MMD_table is 2-dimensional only and totally static.
Furthermore it doesn't really fit into method lookups as it's an
assymmetric second case.

1) Single method lookup.

Current state: works for objects and NCI class methods. Does not work
dynamically for vtable methods.

The switch-over from dynamic lookup with objects to static lookup in
PMCs is done with two helper (meta-)classes: delegate.pmc for objects
and deleg_pmc.pmc for objects derived from PMCs). This adds some extra
C<if> statements in find_method_direct and looks bulky.

Proposal:

We just do a method call for all method-like, "user" methods that
are currently handled in vtables. This means that we have internally:

  array."__push"()
  array."__get_integer_keyed"()
  scalar."__get_string"()

and what not.

But also:

  complex."imag"()
  complex."real"()
  io_pmc."eof"()
  ...

The existing opcode syntax remains of course, but the method call
syntax is an equivalent.

Please remember, when reading this that we are currently not discussing
performance, we want a complete and correct implementation. We can deal
with performance implications later.

The vtable entry can remain for internal (inside Parrot) use, if we know
which PMC type is used and for internal vtable methods like init, mark,
destroy, freeze, thaw, hash (!), and so on.

As there is no distinction between a method and what's currently a
vtable this expands easily to pythonic add-ons like PyInt."__oct__"
which isn't supported directly and of course to all object methods.

There is no distinction between object and vtable class methods (except
that some cases may be heavily optimized).

2) 2-dimensional MMD

This is basically just an abstraction of 1). A MMD method gets 2 entries
in the globals table, one for the left class namespace and one for the
right class. We have e.g.

the visible opcode

   Pdest = Pleft + Pright

This gets an internal opcode:

  callmethod_MMD_2 "add"         # 2-dim MMD dispatch opcode

or a more specialized one with signature and arguments:

  callmethod_MMD_2_v_ppp "add", Pdest, Pleft, Pright

to save on register setup overhead.

This opcode does:
a) look in Pleft's class for methods named "add", remember the tuple
   (function, C<searchoffset>) for each found method
b) look in PRight's class and create such tuples, where the 2nd function
   argument is PRight's class. To accomplish this the namepace that is
   searched is e.g. "\0right_class\0__2".
c) compare the two lists for the best match (based on some distance e.g.
   the combined depth (searchoffset) of the found functions)
d) cache the result (function, left-type, right-type)
e) call function

Done.

Further as the classes for left and right are responsible for the method
lookup, the left class can e.g. just ignore the MMD-search by returning
a function and a flag that no further search should be done.

During class setup existing MMD functions in *.pmc are created by a
sequence similar to:

  store_global "class_name_left", "add", func
  store_global "class_name_right", 2, "add", func

or

  store_global "class_name_right\0__2", "add", func


3) n-dimensional MMD

This is a straight-forward extension of 2) and handled by

  callmethod_MMD_3_sig "func"      (maybe)
  ...
  callmethod_MMD_n "func", n

Comments welcome,

leo

Reply via email to