Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Premature pessimization

60 views
Skip to first unread message

Leopold Toetsch

unread,
Dec 5, 2004, 8:00:58 AM12/5/04
to Perl 6 Internals
This term came up in a recent discussion[1]. But I'd like to give this
term a second meaning.

During design considerations we (including me of course too) tend to
discard or pessimize ideas early, because they look inefficient. Recent
examples are e.g.
- spilling
- lexical (re-)fetching
- method calls

We have even some opcodes that work around the estimated bad effect of
the operation. E.g. for attribute access:

classoffset Ix, Pobj, "attr"
getattribute Pattr, Pobj, Ix

instead a plain and clear, single opcode:

gettatribute Pattr, Pobj, "attr"

We are thinking that the former is more efficient because we can cache
the expensive hash lookup in the index C<Ix> and do just integer math to
access other attributes. (This is BTW problematic anyay, as the side
effect of a getattribute could be a change to the class structure).

Anyway, a second example is the indexed access of lexicals additionally
to the named access. Again a premature pessimization with opcode support.

Another one is the "newsub" opcode, invented to be able to create the
subroutine object (and possibly the return continuation) outside of a
loop, where the function is called.

All of these pessimized operations have one common part: one or several
costy lookups with a constant key.

One possible solution is inline caching.

A cache is of course kind of an optimization. OTOH when we know that we
don't have to pay any runtime penalty for certain operations, possible
solutions are again thinkable that would otherwise just be discarded as
they seem to be expensive.

I'll comment on inline caching in a second mail.

leo

[1] Michael Walter in Re: [CVS ci] opcode cleanup 1 . minus 177 opcodes
I'm fully behind Dan's answer - first fix broken stuff, then optimize.
OTOH when compilers already are choking on the source it seems that this
kind of pessimization isn't really premature ;)

Luke Palmer

unread,
Dec 5, 2004, 1:46:24 PM12/5/04
to Leopold Toetsch, Perl 6 Internals
Leopold Toetsch writes:
> This term came up in a recent discussion[1]. But I'd like to give this
> term a second meaning.

Except what you're talking about here is premature *optimzation*.
You're expecting certain forms of the opcodes to be slow (that's the
pessimization part), but then you're acutally using opcodes that you
think can be made faster. This is a classic Knuth example.

If I were Dan, here's what I'd say (though perhaps I'd say it in
somewhat a different tone :-): don't worry about it. Inline caching is
just another optimization. We need to be feature complete.

Leo, speed is never off your mind, so we can be fairly certain that we
won't be making any decisions that are going to bite us speed-wise.
Plus, at this point, we can change interfaces (when we go past feature
complete into real-life benchmarked optimization). Yeah, the compilers
will have to change, but really that's not a big issue. I've been
writing compilers for parrot for a while, and stuff is always changing,
and it usually means one or two lines of code for me if I designed well.

And if you really feel like you need to optimize something, look into
the lexicals-as-registers idea you had to fix continuation semantics.
Then you can work under the guise of fixing something broken.

Luke

Ashley Winters

unread,
Dec 5, 2004, 8:49:19 PM12/5/04
to Luke Palmer, Leopold Toetsch, Perl 6 Internals
On Sun, 5 Dec 2004 11:46:24 -0700, Luke Palmer <lu...@luqui.org> wrote:
> Leopold Toetsch writes:
> > This term came up in a recent discussion[1]. But I'd like to give this
> > term a second meaning.
>
> Except what you're talking about here is premature *optimzation*.
> You're expecting certain forms of the opcodes to be slow (that's the
> pessimization part), but then you're acutally using opcodes that you
> think can be made faster. This is a classic Knuth example.

So the sequence of using classoffset/getattribute is a _feature_
necessary for completeness, rather than a "pessimization" to
compensate for the belief that not explicitly caching would be
hopelessly slow? Ahh. I'm learning much. :)

Ashley Winters

Michael Walter

unread,
Dec 5, 2004, 8:47:56 PM12/5/04
to Luke Palmer, Leopold Toetsch, Perl 6 Internals
On Sun, 5 Dec 2004 11:46:24 -0700, Luke Palmer <lu...@luqui.org> wrote:
> Leopold Toetsch writes:
> > This term came up in a recent discussion[1]. But I'd like to give this
> > term a second meaning.
>
> Except what you're talking about here is premature *optimzation*.
Yes, indeed.

Cheers,
Michael

Vema Venkata

unread,
Dec 5, 2004, 9:02:11 PM12/5/04
to Ashley Winters, Luke Palmer, Perl 6 Internals
can you unsubscribe me asap

rgds
venkat

Leopold Toetsch

unread,
Dec 6, 2004, 5:05:42 AM12/6/04
to Luke Palmer, perl6-i...@perl.org
Luke Palmer <lu...@luqui.org> wrote:
> Leopold Toetsch writes:
>> This term came up in a recent discussion[1]. But I'd like to give this
>> term a second meaning.

> Except what you're talking about here is premature *optimzation*.

No. I don't think so.

>> During design considerations we (including me of course too) tend to
>> discard or pessimize ideas early, because they look inefficient

And I've summarized a bunch of examples. Maybe it wasn't too clear, but
the conclusion is of course: spilling, lexical refetching, using
method calls, ... (expensive looking operations) should not be discarded
early. They can be optimized *later*.

> ... Inline caching is


> just another optimization. We need to be feature complete.

That's exactly what I've written. I've described this idea as a
possible later optimization.

> And if you really feel like you need to optimize something, look into
> the lexicals-as-registers idea you had to fix continuation semantics.
> Then you can work under the guise of fixing something broken.

Yeah. Have a look at chromatic's 4 c-words:

compiles -> correct -> complete -> competitive

"compiles" isn't really given, when there are compilers that either
can't compile an -O3 build of the switched core or take ages to
complete (if memory usage even permits that) choking the CG* cores.

"correct". I've discovered and analysed the problem with continuations.
I've made a proposal to fix that. No one has said that it's technically
wrong or couldn't work. It seems you are liking the idea, but Dan
doesn't. Now what?

"complete" - read e.g. my recent postings WRT MMD (and perl.cvs.parrot:)

"competitive" well, I like a speedy Parrot, that's obvious. It's a nice
to have. But not only. Folks on conferences get interested in Parrot
because it can proof that programs will run faster.

> Luke

leo

Leopold Toetsch

unread,
Dec 6, 2004, 5:39:55 AM12/6/04
to Ashley Winters, Luke Palmer, Perl 6 Internals

<citing Luke Palmer>
On a semi-related note, can I get a classoffset without doing a hash
lookup? That is, can I store the class number I get assigned somewhere
for quick fetching?

*SCNR* - leo

Sam Ruby

unread,
Dec 6, 2004, 9:00:36 AM12/6/04
to l...@toetsch.at, perl6-i...@perl.org
Leopold Toetsch wrote:
>
> "correct". I've discovered and analysed the problem with continuations.
> I've made a proposal to fix that. No one has said that it's technically
> wrong or couldn't work. It seems you are liking the idea, but Dan
> doesn't. Now what?

I would suggest focusing on one issue at a time and starting with
writing a test case.

But, overall, it is clear that you are frustrated. It show when you
give responses like "Doesn't really matter" when people like me ask
questions about your proposals. That, in turn, makes people like me
frustrated.

Re: classoffset... I don't currently use this opcode, nor do I plan to.
This opcode has a builtin assumption that attributes are stored as
attributes. They may in fact be methods or properties in the Parrot
sense, or Property's in the Python sense.

Re: VTABLES... I disagree with you on this one. Prematurely mapping an
operation to a string is a premature pessimization. Add to that the
fact that such names can conflict with usages by languages of this
runtime. Overall, the design of the opcodes and PMC layout should focus
on trying to retain as much information as possible.

Re: continuations... frankly, I'm hoping that a solution emerges that
doesn't involve significant reduction in functionallity. I might be
misunderstanding you, but it sounds to me like you are proposing
ditching lexical pads.

- Sam Ruby


Leopold Toetsch

unread,
Dec 6, 2004, 10:25:43 AM12/6/04
to Sam Ruby, perl6-i...@perl.org
Sam Ruby <ru...@intertwingly.net> wrote:
> Leopold Toetsch wrote:
>>
>> "correct". I've discovered and analysed the problem with continuations.
>> I've made a proposal to fix that. No one has said that it's technically
>> wrong or couldn't work. It seems you are liking the idea, but Dan
>> doesn't. Now what?

> I would suggest focusing on one issue at a time and starting with
> writing a test case.

> But, overall, it is clear that you are frustrated.

... a bit by the lack of progress that can be achieved to e.g. fix
broken continuation behavior. But not much ;)

> ... It show when you


> give responses like "Doesn't really matter" when people like me ask
> questions about your proposals. That, in turn, makes people like me
> frustrated.

Well, you worried about different classes having identical method names,
but the methods do different things. I asked why this is a problem. I
gave an example. Here is one more:

obj."__set_integer_native"(10)

does 2 totally different things for arrays (set array size) or for
scalars (assign value 10).

> Re: VTABLES... I disagree with you on this one. Prematurely mapping an
> operation to a string is a premature pessimization.

Except that we are doing that already. Please read through
classes/delegate.c. The problem is that this scheme doesn't work for
MMD of real objects.

> ... Add to that the


> fact that such names can conflict with usages by languages of this
> runtime.

Parrots method names (two leading underscores + vtable name) are
reserved. And again, when two distinct clases use the same method name
this is no conflict at all. Issues with classes in an inheritance chain
are easily avoided by following that convention.

> ... Overall, the design of the opcodes and PMC layout should focus


> on trying to retain as much information as possible.

Nothing get lost. Visible opcodes don't change. An example

.sub m
$P0 = newclass "Foo"
$I0 = find_type "Foo"
.local pmc obj
obj = new $I0
obj = 5
.end

running that snippet gives:

Can't find method '__set_integer_native' for object 'Foo'.

The vtable method set_integer_native clearly maps to a real method that
can be either inherited or be provided by the user. This doesn't work
for MMD functions.

> Re: continuations... frankly, I'm hoping that a solution emerges that
> doesn't involve significant reduction in functionallity. I might be
> misunderstanding you, but it sounds to me like you are proposing
> ditching lexical pads.

No. I'm not ditching lexical pads at all. They are of course needed. The
top pad is in the registers. Outer pads are looked up as usual.

> - Sam Ruby

leo

Sam Ruby

unread,
Dec 6, 2004, 11:11:59 AM12/6/04
to l...@toetsch.at, perl6-i...@perl.org
Leopold Toetsch wrote:

> Sam Ruby <ru...@intertwingly.net> wrote:
>
>>Leopold Toetsch wrote:
>>
>>>"correct". I've discovered and analysed the problem with continuations.
>>>I've made a proposal to fix that. No one has said that it's technically
>>>wrong or couldn't work. It seems you are liking the idea, but Dan
>>>doesn't. Now what?
>
>>I would suggest focusing on one issue at a time and starting with
>>writing a test case.
>
>>But, overall, it is clear that you are frustrated.
>
> ... a bit by the lack of progress that can be achieved to e.g. fix
> broken continuation behavior. But not much ;)

My philosophy is simple: things without test cases tend not not get
fixed, and when fixed, tend not to stay fixed.

>>... It show when you
>>give responses like "Doesn't really matter" when people like me ask
>>questions about your proposals. That, in turn, makes people like me
>>frustrated.
>
> Well, you worried about different classes having identical method names,
> but the methods do different things. I asked why this is a problem. I
> gave an example. Here is one more:
>
> obj."__set_integer_native"(10)
>
> does 2 totally different things for arrays (set array size) or for
> scalars (assign value 10).

I am worried about Parrot trying to establish common public names for
common functions. Many of the examples you gave did not include the
prerequisite double underscores. For example: "sub", "imag", "eof".
These names are not likely to have a commmon behavior across all languages.

>>Re: VTABLES... I disagree with you on this one. Prematurely mapping an
>>operation to a string is a premature pessimization.
>
> Except that we are doing that already. Please read through
> classes/delegate.c. The problem is that this scheme doesn't work for
> MMD of real objects.

I don't know enough to have an informed opinion yet on MMD. But
__set_integer_native is not a MMD operation. It already is efficiently
dispatched to the correct method. What do we benefit from the premature
pessimisation of mapping this to a string?

>>... Add to that the
>>fact that such names can conflict with usages by languages of this
>>runtime.
>
> Parrots method names (two leading underscores + vtable name) are
> reserved. And again, when two distinct clases use the same method name
> this is no conflict at all. Issues with classes in an inheritance chain
> are easily avoided by following that convention.

Again, my point is that the examples need to follow that convention.
Without exception.

>>... Overall, the design of the opcodes and PMC layout should focus
>>on trying to retain as much information as possible.
>
> Nothing get lost. Visible opcodes don't change. An example
>
> .sub m
> $P0 = newclass "Foo"
> $I0 = find_type "Foo"
> .local pmc obj
> obj = new $I0
> obj = 5
> .end
>
> running that snippet gives:
>
> Can't find method '__set_integer_native' for object 'Foo'.
>
> The vtable method set_integer_native clearly maps to a real method that
> can be either inherited or be provided by the user. This doesn't work
> for MMD functions.

Again, set_integer_native is not an MMD function?

>>Re: continuations... frankly, I'm hoping that a solution emerges that
>>doesn't involve significant reduction in functionallity. I might be
>>misunderstanding you, but it sounds to me like you are proposing
>>ditching lexical pads.
>
> No. I'm not ditching lexical pads at all. They are of course needed. The
> top pad is in the registers. Outer pads are looked up as usual.

I guess I don't understand. I guess it is time for a test case. ;-)
How would the following work if the top pad is in registers?

var = 1
def g():
global var
var = 2

print "before", var
g()
print "after", var

Such behavior is the default for perl5:

my $var = 1;
sub g {
$var = 2;
}

print "before $var\n";
g();
print "after $var\n";

- Sam Ruby

Leopold Toetsch

unread,
Dec 6, 2004, 12:45:01 PM12/6/04
to Sam Ruby, perl6-i...@perl.org
Sam Ruby <ru...@intertwingly.net> wrote:
> Leopold Toetsch wrote:

> My philosophy is simple: things without test cases tend not not get
> fixed, and when fixed, tend not to stay fixed.

There is of course a test case. I have mentioned it at least 20 times ;)
t/op/gc_13.imc - currently using lexicals.

> I am worried about Parrot trying to establish common public names for
> common functions. Many of the examples you gave did not include the
> prerequisite double underscores. For example: "sub", "imag", "eof".

Ah ok. Sorry. "__subtract". OTOH some might be that common and the usage
is the same in all languages that we might use that common name. But
that's probably not worth the effort. So yes, we should establish the
notion that all methods follow that convention.

>>>Re: VTABLES... I disagree with you on this one. Prematurely mapping an
>>>operation to a string is a premature pessimization.
>>
>> Except that we are doing that already. Please read through
>> classes/delegate.c. The problem is that this scheme doesn't work for
>> MMD of real objects.

> I don't know enough to have an informed opinion yet on MMD. But
> __set_integer_native is not a MMD operation. It already is efficiently
> dispatched to the correct method.

For PMCs yes. For objects not efficiently and only with a separate
delegate meta-class.

> ... What do we benefit from the premature


> pessimisation of mapping this to a string?

Well, method names happen to be strings ;)

Anyway, I'll try to summarize our current method dispatch scheme:

vtable MMD NCI method
-------------------------------------------------------------
opcode set P0, 4 add P0, P1, P2 io."__eof"()
-------------------------------------------------------------
PMC pmc->vtable->.. mmd_dispatch_* callmethod
object delegate.c 1) callmethod
object(PMC) deleg_pmc.c 1) callmethod

NCI methods are working, the method lookup is dynamic, inheritance
works.

MMD inheritance is totally static (set up during PMC compilation).
PMCs dispatch with the mmd_dispatch_* functions in ops/*.ops.
1) overloading a MMD infix operation needs the mmdvtregister opcode, but
this does not effect any class inheritance and it's just for the given
two types.
Multi-dimensional MD is not implemented.

For vtables objects and objects derived from PMCs use two helper classes
that bridge the dynamic inheritance of objects to the static inheritance
in PMCs. This doesn't support runtime overloading of methods that
defaulted to the PMC method.

Looking at 5 different schemes that work for ~50% of the cases can -
well - make one pessimistic ;)

I'm proposing that *internally* (implementation detail ...) one scheme
should be enough. Again: the opcodes don't change.

>> The vtable method set_integer_native clearly maps to a real method that

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^


>> can be either inherited or be provided by the user. This doesn't work
>> for MMD functions.

> Again, set_integer_native is not an MMD function?

__set_integer_native is a vtable method.

>> No. I'm not ditching lexical pads at all. They are of course needed. The
>> top pad is in the registers. Outer pads are looked up as usual.

> I guess I don't understand. I guess it is time for a test case. ;-)
> How would the following work if the top pad is in registers?

The top pad is always the currently executing one.

> var = 1
> def g():
> global var
> var = 2

> print "before", var
> g()
> print "after", var

It's obviously up to the "global" to do the right thing. My impression
(I don't have more Python knowledge ;) is, that "global" refers to the
outermost lexical pad in the main module.

> Such behavior is the default for perl5:

> my $var = 1;
> sub g {
> $var = 2;
> }

As there is no "my $var" in the inner pad, that's just a C<find_lex>
opcode. It follows the C<prev> pointer to the outer pad and finds in the
lexical hash the "$var" which maps to a position in the register store
of the outer pad.

"my ($a, $b)" in the innermost pad (in sub g) would map directly to
registers as "my $var" maps to a register in "main" (in the outer pad).

It's the same as currently, except that we have now a separate array
that holds the lexicals. I was just mapping that array into the
preserved area of registers, which would make this area of course
variable-sized with the nice benefit that "my int $i" also works (we
don't have natural int lexicals currently).

> - Sam Ruby

leo

Sam Ruby

unread,
Dec 6, 2004, 3:31:54 PM12/6/04
to l...@toetsch.at, perl6-i...@perl.org
Leopold Toetsch wrote:

> Sam Ruby <ru...@intertwingly.net> wrote:
>
>>Leopold Toetsch wrote:
>
>>My philosophy is simple: things without test cases tend not not get
>>fixed, and when fixed, tend not to stay fixed.
>
> There is of course a test case. I have mentioned it at least 20 times ;)
> t/op/gc_13.imc - currently using lexicals.

$ parrot t/op/gc_13.imc
3 * 5 == 15!

What's broken?

>>I am worried about Parrot trying to establish common public names for
>>common functions. Many of the examples you gave did not include the
>>prerequisite double underscores. For example: "sub", "imag", "eof".
>
> Ah ok. Sorry. "__subtract". OTOH some might be that common and the usage
> is the same in all languages that we might use that common name. But
> that's probably not worth the effort. So yes, we should establish the
> notion that all methods follow that convention.

Cool.

>>>>Re: VTABLES... I disagree with you on this one. Prematurely mapping an
>>>>operation to a string is a premature pessimization.
>>>
>>>Except that we are doing that already. Please read through
>>>classes/delegate.c. The problem is that this scheme doesn't work for
>>>MMD of real objects.
>
>>I don't know enough to have an informed opinion yet on MMD. But
>>__set_integer_native is not a MMD operation. It already is efficiently
>>dispatched to the correct method.
>
> For PMCs yes. For objects not efficiently and only with a separate
> delegate meta-class.

The current delegation internals are not likely a good match for
languages like Python or Ruby. I see such languages as implementing
their own semantics for classes, and Parrot limiting its knowledge to
methods like findmeth and invoke.

>>... What do we benefit from the premature
>>pessimisation of mapping this to a string?
>
> Well, method names happen to be strings ;)

Using the table below, at the moment, there are exactly zero strings
materialized and/or compared against during the execution of vtable/PMC
methods. To the extent that these are represent common operations, this
can be significant from a performance perspective.

> Anyway, I'll try to summarize our current method dispatch scheme:
>
> vtable MMD NCI method
> -------------------------------------------------------------
> opcode set P0, 4 add P0, P1, P2 io."__eof"()
> -------------------------------------------------------------
> PMC pmc->vtable->.. mmd_dispatch_* callmethod
> object delegate.c 1) callmethod
> object(PMC) deleg_pmc.c 1) callmethod
>
> NCI methods are working, the method lookup is dynamic, inheritance
> works.
>
> MMD inheritance is totally static (set up during PMC compilation).
> PMCs dispatch with the mmd_dispatch_* functions in ops/*.ops.
> 1) overloading a MMD infix operation needs the mmdvtregister opcode, but
> this does not effect any class inheritance and it's just for the given
> two types.
> Multi-dimensional MD is not implemented.
>
> For vtables objects and objects derived from PMCs use two helper classes
> that bridge the dynamic inheritance of objects to the static inheritance
> in PMCs. This doesn't support runtime overloading of methods that
> defaulted to the PMC method.
>
> Looking at 5 different schemes that work for ~50% of the cases can -
> well - make one pessimistic ;)
>
> I'm proposing that *internally* (implementation detail ...) one scheme
> should be enough. Again: the opcodes don't change.

I don't think that there can be a single dynamic mechanism that works
for all languages, let alone one that works for Parrot internals too.

For starters, "findmeth" is a method. One that merits its own VTABLE
entry (otherwise, how would you find it?). Others that map cleanly onto
existing language syntax also can benefit from such optimizations.

MMD might help out with mutiple language interop, but Python as
currently designed doesn't need any such facility.

>>>The vtable method set_integer_native clearly maps to a real method that
>
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>
>>>can be either inherited or be provided by the user. This doesn't work
>>>for MMD functions.
>
>>Again, set_integer_native is not an MMD function?
>
> __set_integer_native is a vtable method.

Cool.

I asked my question poorly, and I think you answered it, but the
important point is that subroutines can change the lexical variables of
their callers - enough so that either a second level of indirection is
required (such as Dan recently indicated is that plans for Perl6 and
Ruby), or subroutines will need to refetch lexicals after a subroutine call.

- Sam Ruby

Luke Palmer

unread,
Dec 6, 2004, 1:24:10 PM12/6/04
to Leopold Toetsch, Ashley Winters, Perl 6 Internals
Leopold Toetsch writes:
> <citing Luke Palmer>
> On a semi-related note, can I get a classoffset without doing a hash
> lookup? That is, can I store the class number I get assigned somewhere
> for quick fetching?

Hey now, you're citing the Luke Palmer that writes code. Don't confuse
him with the Luke Palmer who does software design. They really don't
get along so well...

Luke

Leopold Toetsch

unread,
Dec 7, 2004, 4:03:28 AM12/7/04
to Sam Ruby, perl6-i...@perl.org
Sam Ruby <ru...@intertwingly.net> wrote:
> Leopold Toetsch wrote:

>> There is of course a test case. I have mentioned it at least 20 times ;)
>> t/op/gc_13.imc - currently using lexicals.

> $ parrot t/op/gc_13.imc
> 3 * 5 == 15!

> What's broken?

By using lexicals it works now.

> The current delegation internals are not likely a good match for
> languages like Python or Ruby. I see such languages as implementing
> their own semantics for classes, and Parrot limiting its knowledge to
> methods like findmeth and invoke.

Another good reason to use pmc->vtable->fine_method in *all* lookups. So
the PMC has full control over the dispatch.

>>>... What do we benefit from the premature
>>>pessimisation of mapping this to a string?
>>
>> Well, method names happen to be strings ;)

> Using the table below, at the moment, there are exactly zero strings
> materialized and/or compared against during the execution of vtable/PMC
> methods.

I don't get that sentence.

> ... To the extent that these are represent common operations, this


> can be significant from a performance perspective.

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Ha? *SCNR*

>> I'm proposing that *internally* (implementation detail ...) one scheme
>> should be enough. Again: the opcodes don't change.

> I don't think that there can be a single dynamic mechanism that works
> for all languages, let alone one that works for Parrot internals too.

What's wrong with the find_method vtable?

> For starters, "findmeth" is a method. One that merits its own VTABLE
> entry (otherwise, how would you find it?).

Exactly. The "find_method" vtable is responsible for locating the
method. As such it can't be overloaded directly. The "find_method"
vtable is part of the meta-class system inside PMCs. The meta-class for
Parrot standard objects is ParrotObject which handles the "find-method"
by calling code in objects.c.

If that dispatch scheme doesn't fit at all for a language it can of
course create it's own meta-class with an appropriate "find_method"
vtable. The important thing is that from the opcode level all continues
to work as long as the opcodes are using "find_method".

> MMD might help out with mutiple language interop, but Python as
> currently designed doesn't need any such facility.

That's not quite true. CPython has a rather bulky manual dispatch to
find the correct operation for e.g. "long + int". The result is totally
the same with Parrot's MMD dispatch - find a possibly internal function
that is able to add a long integer and a normal integer.

You can now of course duplicate the whole standard PMCs and roll your
own code. But that's error prone and increases code size for no good
reason and it will verly likely not help for HLL interoperbility.

> I asked my question poorly, and I think you answered it, but the
> important point is that subroutines can change the lexical variables of
> their callers - enough so that either a second level of indirection is
> required

The second level is the name hash. Nothing changes here. If the compiler
knows the lexical it can currently emit code with an indexed access to
the lexical data array. This corresponds to an indexed access inside the
register store. If the lexical isn't known because it's somewhere in an
outer pad (or it's even created dynamically) the hash lookup jumps in,
as now.

> - Sam Ruby

leo

Sam Ruby

unread,
Dec 7, 2004, 10:26:26 AM12/7/04
to l...@toetsch.at, perl6-i...@perl.org
Leopold Toetsch wrote:
>
>>The current delegation internals are not likely a good match for
>>languages like Python or Ruby. I see such languages as implementing
>>their own semantics for classes, and Parrot limiting its knowledge to
>>methods like findmeth and invoke.
>
> Another good reason to use pmc->vtable->fine_method in *all* lookups. So
> the PMC has full control over the dispatch.

How does one lookup the C<find_method> method? That will remain a
VTABLE, entry right?

All *external* names should be looked up using find_method.

All names needed by the Parrot runtime need to be orthogonal to the set
of names available for use by languages. Ideally this would be by
virtue of using a separate mechanism (e.g., VTABLES), but acceptably it
could be done by naming convention (leading double underscores with no
trailing double underscores).

We also need to be aware that in the general case, we are talking about
two lookups. One to find the language specific wrapper. And one to
find the common code which backs it.

The second dispatch may be spelled "string_str_index", in which case the
loader does all the necessary fixup. The second dispatch may be spelled
"VTABLE_get_pmc_keyed" in which case we are looking at a couple of
pointer hops and some integer arithmetic. The second dispatch may be
spelled "SUPER()" and use some combination of these. Or it could be
using find_method, or perhaps even another technique entirely.

But in all cases, we are looking at two different things.

= = =

Why is this issue so important to me? I see a lot of things I like
about Parrot, but at the moment, the notions that are baked into the
core as to how classes should work is not one of them.

I see a change that went in today to invalidate a method cache if a
store_global call is made. That presumes a lot about how find_method
works internally. An assumption that will not be valid for a number of
languages.

>>>>... What do we benefit from the premature
>>>>pessimisation of mapping this to a string?
>>>
>>>Well, method names happen to be strings ;)
>
>>Using the table below, at the moment, there are exactly zero strings
>>materialized and/or compared against during the execution of vtable/PMC
>>methods.
>
> I don't get that sentence.

VTABLE_xxx depends only on pointer arithmetic and dereferencing. Yes,
20% of the operations may need more, and that should be provided for,
but if 80% of the calls can be done this way, the performance benefits
are significant.

As you tirelessly point out, this is all internal. The way the ops are
coded in the IMCC source need not change. However, prematurely mapping
*all* method names to strings so that a second method dispatch can be
done in 100% of the cases is a premature pessimization.

= = =

I plan to spend the next day or so looking into catching named
exceptions, after which point I plan to implement Python classes on
Parrot. I do not anticipate using globals or ParrotObject or
ParrotClass in that implementation. I expect that there will be tests
that replace methods, and I hope that optimizations that attempt to
cache the results of find_method don't prevent these updates from being
seen.

I don't believe that it is a good idea for Python specific
functionallity to be present in the core Parrot runtime. For that
reason, I will implement this functionality inside dynclasses. If the
runtime provides reasonable hooks for the functionally, I will use them.
If not, I will temporarily clone and modify what I need, with the
intent of getting it working first, and then refactoring the appropriate
parts back into the Parrot runtime, this time with the necessary
intercept points. In rare cases - when I feel confident enough - I may
modify the Parrot runtime to provide the hooks I need.

And all of this will be backed by test cases so that such refactoring
can be done confidently and correctly.

If anybody has any issues with this plan, please let me know now.

- Sam Ruby

Leopold Toetsch

unread,
Dec 7, 2004, 11:55:25 AM12/7/04
to Sam Ruby, perl6-i...@perl.org
Sam Ruby <ru...@intertwingly.net> wrote:
> Leopold Toetsch wrote:

>> Another good reason to use pmc->vtable->fine_method in *all* lookups. So
>> the PMC has full control over the dispatch.

> How does one lookup the C<find_method> method? That will remain a
> VTABLE, entry right?

Yes of course.

> All *external* names should be looked up using find_method.

Yes. But what's an external name? What happens if a Perl6 guru installs
a global overloaded add function:

multi sub *infix:<+>(Int $l, Int $r) { ... }

for example to count all "add" operations or whatever. This can
currently be done with the C<mmdvtregister> opcode. But that installs only
one MMD function for one type pair. What if some classes inherit the
"__add" method from C<Int>. Or:

multi sub *infix:<+>(Any $l, Any $r) { ... }

which presumably would influence all Perl types.

Citing S06: "Operators are just subroutines with special names."

Doing the same overloading with prefix or postfix operators OTOH would
change vtable methods. That's currently not possible because the vtable
dispatch is static, except for objects where it's dynamic.

> We also need to be aware that in the general case, we are talking about
> two lookups. One to find the language specific wrapper. And one to
> find the common code which backs it.

Yes, but when the HLL method is found (e.g. PyStr.index) you just call
the implementation statically and adjust e.g. return values.

> The second dispatch may be spelled "string_str_index",

... the second dispatch is basically not dispatch, it's a function call.

> Why is this issue so important to me? I see a lot of things I like
> about Parrot, but at the moment, the notions that are baked into the
> core as to how classes should work is not one of them.

You can straightforwardly use Parrot's object system for attributes and
methods with all stuff known at compile time, AFAIK. You basically just
extend the find_method and get_attr_str vtables.

WRT find_method: S13 mentions multi subs per package or even lexically
scoped. So we'll probably have to extend the method lookup anyway.

> I see a change that went in today to invalidate a method cache if a
> store_global call is made. That presumes a lot about how find_method
> works internally. An assumption that will not be valid for a number of
> languages.

Well, the builtin method lookup system with the default find_method
implementation is using it. But the cache is fully transparent.

> VTABLE_xxx depends only on pointer arithmetic and dereferencing. Yes,
> 20% of the operations may need more, and that should be provided for,
> but if 80% of the calls can be done this way, the performance benefits
> are significant.

Please don't start arguing with estimated performance benefits. I've
already shown that we can do the current MMD operations 30% faster -
but with dynamic dispatch too.
We need at the opcode level a dynamic dispatch. Internally the vtable
call remains. I've written that already a few times.

> As you tirelessly point out, this is all internal. The way the ops are
> coded in the IMCC source need not change. However, prematurely mapping
> *all* method names to strings so that a second method dispatch can be
> done in 100% of the cases is a premature pessimization.

Well better schemes for method overloading (e.g. in Python metaclass)
are always welcome. I've proposed a scheme. And yes, it's an
implementation detail.

[ dynclasses ]

> If anybody has any issues with this plan, please let me know now.

Python specific stuff should of course move out from core. For the rest:

It depends. If you end with a duplicate of CPython's Objects directory
interoperbility will be difficult.

> - Sam Ruby

leo

Sam Ruby

unread,
Dec 7, 2004, 2:20:21 PM12/7/04
to l...@toetsch.at, perl6-i...@perl.org
Leopold Toetsch wrote:

> Sam Ruby <ru...@intertwingly.net> wrote:
>
>>Leopold Toetsch wrote:
>
>>>Another good reason to use pmc->vtable->fine_method in *all* lookups. So
>>>the PMC has full control over the dispatch.
>
>>How does one lookup the C<find_method> method? That will remain a
>>VTABLE, entry right?
>
> Yes of course.

So *all* lookups (complete with the asterisks) does not mean *all* lookups.

How about <invoke>?

>>All *external* names should be looked up using find_method.
>
> Yes. But what's an external name? What happens if a Perl6 guru installs
> a global overloaded add function:
>
> multi sub *infix:<+>(Int $l, Int $r) { ... }
>
> for example to count all "add" operations or whatever. This can
> currently be done with the C<mmdvtregister> opcode. But that installs only
> one MMD function for one type pair. What if some classes inherit the
> "__add" method from C<Int>. Or:
>
> multi sub *infix:<+>(Any $l, Any $r) { ... }
>
> which presumably would influence all Perl types.
>
> Citing S06: "Operators are just subroutines with special names."

That statement is true for Perl. Same statement is true for Python.
But the names vary based on the language.

IMCC should be independent of Perl semantics.

> Doing the same overloading with prefix or postfix operators OTOH would
> change vtable methods. That's currently not possible because the vtable
> dispatch is static, except for objects where it's dynamic.
>
>>We also need to be aware that in the general case, we are talking about
>>two lookups. One to find the language specific wrapper. And one to
>>find the common code which backs it.
>
> Yes, but when the HLL method is found (e.g. PyStr.index) you just call
> the implementation statically and adjust e.g. return values.
>
>>The second dispatch may be spelled "string_str_index",
>
> ... the second dispatch is basically not dispatch, it's a function call.

So far, I have utterly failed to get my point across.

Either all languages are going to need to adopt a common set of special
names (not going to happen), or Parrot is a single language runtime, or
the mechanism provided to do a language level dispatch needs to be
orthogonal to the way that Parrot internal dispatches are done.

Currently, Parrot is the latter. It is the suggestion that it moves
towards the previous alternative that I object to.

>>Why is this issue so important to me? I see a lot of things I like
>>about Parrot, but at the moment, the notions that are baked into the
>>core as to how classes should work is not one of them.
>
> You can straightforwardly use Parrot's object system for attributes and
> methods with all stuff known at compile time, AFAIK. You basically just
> extend the find_method and get_attr_str vtables.

"straighforwardly"... "known at compile time"?

Python's classes are glorified hashes, populated at runtime. The are
essentially anonymous and lexically scoped.

> WRT find_method: S13 mentions multi subs per package or even lexically
> scoped. So we'll probably have to extend the method lookup anyway.
>
>>I see a change that went in today to invalidate a method cache if a
>>store_global call is made. That presumes a lot about how find_method
>>works internally. An assumption that will not be valid for a number of
>>languages.
>
> Well, the builtin method lookup system with the default find_method
> implementation is using it. But the cache is fully transparent.
>
>>VTABLE_xxx depends only on pointer arithmetic and dereferencing. Yes,
>>20% of the operations may need more, and that should be provided for,
>>but if 80% of the calls can be done this way, the performance benefits
>>are significant.
>
> Please don't start arguing with estimated performance benefits. I've
> already shown that we can do the current MMD operations 30% faster -
> but with dynamic dispatch too.
> We need at the opcode level a dynamic dispatch. Internally the vtable
> call remains. I've written that already a few times.

I think that all we can agree upon here is the MMD support is both
incomplete and unoptimized. Making decisions based on how this
implementation performs is premature.

>>As you tirelessly point out, this is all internal. The way the ops are
>>coded in the IMCC source need not change. However, prematurely mapping
>>*all* method names to strings so that a second method dispatch can be
>>done in 100% of the cases is a premature pessimization.
>
> Well better schemes for method overloading (e.g. in Python metaclass)
> are always welcome. I've proposed a scheme. And yes, it's an
> implementation detail.

I watched the CLR folks try to come to consensus on as simple a matter
as multiple inheritance. Each language will aproach this differently.
The best Parrot can hope to do is to standardize on a protocol, and to
provide enough primitives to enable languages to build proper support.

> [ dynclasses ]
>
>>If anybody has any issues with this plan, please let me know now.
>
> Python specific stuff should of course move out from core. For the rest:
>
> It depends. If you end with a duplicate of CPython's Objects directory
> interoperbility will be difficult.

If interoperability is defined as implementing a language independent
protocol, then interoperability won't be a problem.

If interoperability is defined by adopting exactly the Perl mechanisms
for defining classes and adopting exactly the Perl names for methods,
then, yes interoperability will be difficult.

- Sam Ruby

Leopold Toetsch

unread,
Dec 8, 2004, 4:19:10 AM12/8/04
to Sam Ruby, perl6-i...@perl.org
Sam Ruby <ru...@intertwingly.net> wrote:
> Leopold Toetsch wrote:

> So *all* lookups (complete with the asterisks) does not mean *all* lookups.

> How about <invoke>?

Let's first concentrate on simpler stuff like infix operators.

>> Citing S06: "Operators are just subroutines with special names."

> That statement is true for Perl. Same statement is true for Python.
> But the names vary based on the language.

Yes. So let's factor out the common part and have that in Parrot core,
usable for Python and Perl and ...

The PyInt PMC currently duplicates almost all functionality that
*should* be in the Integer PMC. We have first to fix the Integer PMC to
do the Right Thing. Then we need some syntax for multiple inheritance in
PMCs. The same holds for other PMCs. It was already proposed that we
should have a language-neutral Hash PMC.

So given that we have a set of language-neutral PMCs in core that do the
right thing, Python or Perl PMCs can inherit a lot of functionality from
core PMCs. Language-specific behavior is of course implemented in the
specific PMC.

Second: method dispatch. I've looked a bit into PyObject. It seems that
you start rolling your own method dispatch. Please don't get me wrong,
I'm not criticizing your implementation. It might also be needed for
some reasons I'm just overlooking and it's currently needed because core
functionality isn't totally finished.

Anyway - and please correct me if my assumptions are not true - I'll try
to factor out the common part again.

You have in PyObject e.g.:

METHOD PMC* __add__(PMC *value) {
PMC * ret = pmc_new(INTERP, dynclass_PyObject);
mmd_dispatch_v_ppp(INTERP, SELF, value, ret, MMD_ADD);
return ret;
}

I see six issues with that kind of approach:

* The "__add" method should be in Parrot core. That's what I've
described in the MMD dispatch proposal.
* the method is returning a new PMC. This doesn't follow the signature
of Parrot infix MMD operations.
* well, it's dispatching twice. First the "__add__" method for
PyObjects has to be searched for then the mmd_dispatch is done.
* it'll very likely not work together with other HLLs. It's a
python-only solution.
* rolling your own dispatch still doesn't help, if a metaclass
overloads the C<+> operation
* code duplication

So how would I do it:

* prelim: above mentioned core PMC cleanup is done. Inheritance works:
a PyInt isa(PyObject, Integer)
* the core PMCs define methods, like your "__add__" except that our
naming conventions is "__add". The Python translator needs just
a translation table for the common core methods.
* Method dispatch is done at the opcode level.

add Px, Py, Pz

just does the right thing. It calls the thingy that implements the
"__add" method, being in core or overloaded shouldn't and doesn't
matter. If inheritance changes at runtime it just works.

And the other way round:

Py."__add"(Pz, Px)

is the same. Again it doesn't matter, if it's a core PMC, a Python
PMC or an overloaded PASM/PIR multi sub (or a Python metaclass).
The only difference is the changed signature. But that's how Parrot
core defines overloaded infix operations.

We have to do that anyway. It's just the correct way to go.

(And please no answers WRT efficiency ;-)

leo

Sam Ruby

unread,
Dec 8, 2004, 8:51:31 AM12/8/04
to l...@toetsch.at, perl6-i...@perl.org
Ah! Now we are getting somewhere!

Leopold Toetsch wrote:

> Sam Ruby <ru...@intertwingly.net> wrote:
>
>>Leopold Toetsch wrote:
>
>>So *all* lookups (complete with the asterisks) does not mean *all* lookups.
>
>>How about <invoke>?
>
> Let's first concentrate on simpler stuff like infix operators.

OK, but the point is that there will always be multiple mechanisms for
dispatch.

>>>Citing S06: "Operators are just subroutines with special names."
>
>>That statement is true for Perl. Same statement is true for Python.
>>But the names vary based on the language.
>
> Yes. So let's factor out the common part and have that in Parrot core,
> usable for Python and Perl and ...
>
> The PyInt PMC currently duplicates almost all functionality that
> *should* be in the Integer PMC. We have first to fix the Integer PMC to
> do the Right Thing. Then we need some syntax for multiple inheritance in
> PMCs. The same holds for other PMCs. It was already proposed that we
> should have a language-neutral Hash PMC.

No question that that is the intended final goal. What you see in the
current python dynclasses is not representative of that final goal.

So, why have I proceeded in this manner? Two reasons.

First, I am not about to make random, unproven changes to the Parrot
core until I am confident that the change is correct. Cloning a class
temporarily gives me a playground to validate my ideas.

Second, I am not going to wait around for Warnocked questions and
proposals to be addressed.

Now, neither of the above are absolutes. You have seen me make changes
to the core - but only when I was relatively confident. And I *have*
put on hold trying to reconcile object oriented semantics as this is
both more substantial and seemed to be something that was likely to be
addressed.

Also, while I am not intending to make speculative changes to the core
of Parrot, I don't have any objections to anybody making changes on my
behalf. If you see some way of refactoring "my" code, go for it. It
isn't "mine" - it is the community's.

The one thing I would like to ask is that test cases that currently pass
continue to pass. The dynclass unit tests are part of the normal test.
Additionally, the tests in languages/parrot have been the ones driving
most of my implementation lately.

I do realize that that means checking out Pirate. Even though I don't
agree with it, I do understand Michal's licensing issues. The reason I
am not investing much time in resolving this issue is that Pirate is
exactly one source file and could quickly be rewritten using the Perl 6
Grammar engine once that functionallity becomes sufficiently complete.

> So given that we have a set of language-neutral PMCs in core that do the
> right thing, Python or Perl PMCs can inherit a lot of functionality from
> core PMCs. Language-specific behavior is of course implemented in the
> specific PMC.

Agreed. One area that will require a bit more thought is error cases.
The behavior of integer divide by zero is likely to be different in each
language. This could be approached in a number of different ways. One
is by cloning such methods, like I have done. Another is to wrap such
methods, catch the exception that is thrown, and handle it in a language
specific manner.

A better approach would be for the core to call out to a method on such
error cases. Subclasses could simply inherit the common core behavior
and override this one method. It also means that the "normal" execution
path length (i.e., when dividing by values other than zero) is optimal,
it is only the error paths that involve extra dispatches.

That's an easy case. Overflow is a bit more subtle. Some languages
might want to wrap the results (modulo 2**32). Some languages might
want an exception. Other languages might want promotion to BigInt.

Even if promotion to BigInt were the default behavior, subclasses would
still want to override it. In Python's case, promotion to PyLong (which
ideally would inherit from and trivially specialize and extend BigIt)
would be the desired effect.

Even this is only one aspect of a more general case: all morphing
behavior needs to be overridable by subclasses. I believe that this can
be easily handled by the current Parrot architecture by virtue of the
fact that destination objects must be created before methods are called,
and such destination objects can override morph methods). But it would
help the cause if code were written to promote things to "Integer"
instead of "PerlInt". Yes, at the moment, I'm guilty of this too.

> Second: method dispatch. I've looked a bit into PyObject. It seems that
> you start rolling your own method dispatch. Please don't get me wrong,
> I'm not criticizing your implementation. It might also be needed for
> some reasons I'm just overlooking and it's currently needed because core
> functionality isn't totally finished.

I'll address your questions below, but for reference, here is the code
that Pirate generates for "a=b+c":

find_type $I0, 'PyObject'
new $P0, $I0
find_lex $P1, 'b'
find_lex $P2, 'c'
$P0 = $P1 + $P2
store_lex -1, 'a', $P0

What this means is that the __add__ method will not be directly used for
either PyInt or PyString objects, instead Parrot mechanisms for
dispatching this operation (currently MMD_ADD) will be used.
Ultimately, I hope that this will help with interlanguage interoperability.

> Anyway - and please correct me if my assumptions are not true - I'll try
> to factor out the common part again.
>
> You have in PyObject e.g.:
>
> METHOD PMC* __add__(PMC *value) {
> PMC * ret = pmc_new(INTERP, dynclass_PyObject);
> mmd_dispatch_v_ppp(INTERP, SELF, value, ret, MMD_ADD);
> return ret;
> }
>
> I see six issues with that kind of approach:
>
> * The "__add" method should be in Parrot core. That's what I've
> described in the MMD dispatch proposal.
> * the method is returning a new PMC. This doesn't follow the signature
> of Parrot infix MMD operations.

Here I do think you are misunderstanding. The __add__ method with
precisely that signature and semantics is defined by the Python language
specification. It is (somewhat rarely) used directly, and therefore
must be supported exactly that way.

> * well, it's dispatching twice. First the "__add__" method for
> PyObjects has to be searched for then the mmd_dispatch is done.

What this means is that (in the somewhat rare case) where people write
Python programs that call the __add__ method directly, they will see
some additional execution path length overhead. And there is a piece
that I haven't written yet that will do the reverse: if MMD_ADD is
called on a PyObject that has not provided such behavior, then an any
__add__ method provided needs to be called.

This gets to the core of the extended discussion that we have been
having. Parrot can attempt to find the "one true" behavior for all such
dispatches, and then get all current and future languages to adopt it;
or Parrot can simply provide the raw machinery and common reusable
components, and allow each language to provide their own two way mappings.

I believe that the former is ultimately a dead end. Hence, I advocate
the latter.

> * it'll very likely not work together with other HLLs. It's a
> python-only solution.

I don't expect other languages to call __getitem__ methods, for example.
Nor do I expect Python programs to be aware of other language
conventions. But I do expect PyDict objects to respond to both
get_pmc_keyed requests and __getitem__ requests in exactly the same
manner, and for Pirate generated code to issued calls to the Parrot
get_pmc_keyed version whenever possible.

That's why I like Parrot's mechanisms to different from, and orthogonal
to, all languages conventions.

> * rolling your own dispatch still doesn't help, if a metaclass
> overloads the C<+> operation
> * code duplication
>
> So how would I do it:
>
> * prelim: above mentioned core PMC cleanup is done. Inheritance works:
> a PyInt isa(PyObject, Integer)

Agreed. One of my first patches was to make what little of PMC
inheritance works today to function. More needs to be done here.
Search for SKIP in t/dynclass/pybuiltin.t for an example.

> * the core PMCs define methods, like your "__add__" except that our
> naming conventions is "__add". The Python translator needs just
> a translation table for the common core methods.

In the general case, looking for "reserved" method names at "compile"
time doesn't work. As everything can be overridden, this dispatch must
be done at runtime.

> * Method dispatch is done at the opcode level.
>
> add Px, Py, Pz
>
> just does the right thing. It calls the thingy that implements the
> "__add" method, being in core or overloaded shouldn't and doesn't
> matter. If inheritance changes at runtime it just works.
>
> And the other way round:
>
> Py."__add"(Pz, Px)
>
> is the same. Again it doesn't matter, if it's a core PMC, a Python
> PMC or an overloaded PASM/PIR multi sub (or a Python metaclass).
> The only difference is the changed signature. But that's how Parrot
> core defines overloaded infix operations.

Python classes will still need an __add__ method. And ultimately, you
will find that you have simply replaced the MMD_ADD integer with a
string, but still be faced with the same multi-dimensional dispatch
problem with inheritance, which hasn't been solved.

> We have to do that anyway. It's just the correct way to go.
>
> (And please no answers WRT efficiency ;-)

I do believe that performance and functionallity must be considered
together. Clearly, "a=b+c" and "a=b.__add__(c)" should make use of
common code, but I will unabashedly state that I am willing to optimize
for the former at the expense of the latter. Furthermore, I'm willing
to optimize for integer addition and string concatenation at the expense
of generalized operator overloading. Particularly as that expense is a
single dispatch, and therefore not generally significant in such cases.

IMHO, where prior discussions went off the rails were when significant
architectural changes were proposed in the face of results of
microbenchmarks that may or may not be indicative of real world usage.

I personally don't think that performance considerations should be out
of bounds in these discussions, but that the focus needs to be on
providing initial implemenations of real world languages on top of the
existing infrastructure so that real tradeoffs can be made.

> leo

- Sam Ruby

Leopold Toetsch

unread,
Dec 8, 2004, 10:07:44 AM12/8/04
to Sam Ruby, perl6-i...@perl.org
Sam Ruby <ru...@intertwingly.net> wrote:
> Ah! Now we are getting somewhere!

Yeah. That's the goal.

> So, why have I proceeded in this manner? Two reasons.

Fair enough, both.

>> So given that we have a set of language-neutral PMCs in core that do the
>> right thing, Python or Perl PMCs can inherit a lot of functionality from
>> core PMCs. Language-specific behavior is of course implemented in the
>> specific PMC.

> Agreed. One area that will require a bit more thought is error cases.

Yep. But let's just figure that out later. First the basics.

> I'll address your questions below, but for reference, here is the code
> that Pirate generates for "a=b+c":

> find_type $I0, 'PyObject'
> new $P0, $I0
> find_lex $P1, 'b'
> find_lex $P2, 'c'
> $P0 = $P1 + $P2
> store_lex -1, 'a', $P0

Good. Now Evil Leo (who can't program in Python ;) writes some piece of
code like this:

$ cat m.py
class M(type):
def __new__(meta, name, base, vars):
cls = type.__new__(meta, name, base, vars)
cls.__add__ = myadd
return cls

def myadd(self, r):
return 44 - r

I = M('Int', (int,), {})

i = I(5)
print i
print i + 2

$ python m.py
5
42

> What this means is that the __add__ method will not be directly used for
> either PyInt or PyString objects

Well, and that's not true, IMHO. See above. It has to be part of
Parrot's method dispatch. What if your translator just sees the last 3
lines of the code and M is in some lib? That implies that you either
can't translate to "$P0 = $P1 + $P2", or that you just translate or
alias "__add__" to Parrot's "__add" and let Parrot fiddle around to find
the correct method.

>> * the method is returning a new PMC. This doesn't follow the signature
>> of Parrot infix MMD operations.

> Here I do think you are misunderstanding. The __add__ method with
> precisely that signature and semantics is defined by the Python language
> specification. It is (somewhat rarely) used directly, and therefore
> must be supported exactly that way.

| __add__(...)
| x.__add__(y) <==> x+y

Parrot semantics are that the destination exists. But having a look at
above "myadd", we probably have to adjust the calling conventions for
overloaded infix operators, i.e. return the destination value. Or
provide both schemes ... dunno.

> In the general case, looking for "reserved" method names at "compile"
> time doesn't work.

"__add__" is reserved in Python and corresponds directly to "__add" in
Parrot. I don't think that doesn't work.

> ... As everything can be overridden, this dispatch must
> be done at runtime.

Exactly and that's what I want to achieve.

> I personally don't think that performance considerations should be out
> of bounds in these discussions

I've already shown that it's possible to go with fully dynamic dispatch
*and* 30% faster for MMD and 70% faster for overloaded operations. First
correct and complete, then speed considerations.

> - Sam Ruby

leo

Sam Ruby

unread,
Dec 8, 2004, 11:16:31 AM12/8/04
to l...@toetsch.at, perl6-i...@perl.org

Here's the part that you snipped that addresses that question:

> And there is a piece that I haven't written yet that will do the
> reverse: if MMD_ADD is called on a PyObject that has not provided
> such behavior, then an any __add__ method provided needs to be
> called.

>>>* the method is returning a new PMC. This doesn't follow the signature


>>> of Parrot infix MMD operations.
>
>>Here I do think you are misunderstanding. The __add__ method with
>>precisely that signature and semantics is defined by the Python language
>>specification. It is (somewhat rarely) used directly, and therefore
>>must be supported exactly that way.
>
> | __add__(...)
> | x.__add__(y) <==> x+y
>
> Parrot semantics are that the destination exists. But having a look at
> above "myadd", we probably have to adjust the calling conventions for
> overloaded infix operators, i.e. return the destination value. Or
> provide both schemes ... dunno.

Since you provided an Evil Leo sample, let me provide an Evil Sam sample:

d = {
"__init__": lambda self,x: setattr(self, "value", x),
"__add__": lambda self,x: str(self.value) + str(x.value)
}

def dict2class(d):
class c: pass
c.__dict__.update(d)
return c

c = dict2class(d)

a=c(2)
b=c(3)
print a+b

Things to note:
1) classes which are created every time a function is called
2) classes are thin wrappers over a dictionary object

Now, given the above sample, let's revisit the statement that "The

Python translator needs just a translation table for the common core
methods."

How, exactly, would that be done? Given that the method name is simply
a string... used as a key in dictionary... with a different parameter
signature than the hypothetical Parrot __add method.

That's why I say:

>>In the general case, looking for "reserved" method names at "compile"
>>time doesn't work.

> "__add__" is reserved in Python and corresponds directly to "__add" in
> Parrot. I don't think that doesn't work.

__add__ is *not* reserved in Python. There just is some syntatic sugar
that provide a shorthand for certain signatures. I am free to define
__add__ methods that have zero or sixteen arguments. I won't be able to
call such methods with the convenient shorthand, but other than that,
they should work.

>>I personally don't think that performance considerations should be out
>>of bounds in these discussions
>
> I've already shown that it's possible to go with fully dynamic dispatch
> *and* 30% faster for MMD and 70% faster for overloaded operations. First
> correct and complete, then speed considerations.

Neither of which match Python semantics. We are going to need a system
where classes are anonymous, not global. Where methods are properties
that can be added simply by calling the equivalent of set_pmc_keyed.

- Sam Ruby

Leopold Toetsch

unread,
Dec 8, 2004, 1:49:13 PM12/8/04
to Sam Ruby, perl6-i...@perl.org
Sam Ruby <ru...@intertwingly.net> wrote:
> Leopold Toetsch wrote:

> Here's the part that you snipped that addresses that question:

> > And there is a piece that I haven't written yet that will do the
> > reverse: if MMD_ADD is called on a PyObject that has not provided
> > such behavior, then an any __add__ method provided needs to be
> > called.

Ok. But that would imply that HLL interoperbility isn't really possible. Or
just at a minimal surface level. But see below.

> Since you provided an Evil Leo sample, let me provide an Evil Sam sample:

> d = {
> "__init__": lambda self,x: setattr(self, "value", x),
> "__add__": lambda self,x: str(self.value) + str(x.value)
> }

> def dict2class(d):
> class c: pass
> c.__dict__.update(d)

^^^^^^^^^^^

This is the critical part of it. The "__dict__" of your class provides the
namespace. Setting a key in that namespace (or an attribute of your class
with that key) has a special meaning in Python, *if* that key happens to
be one of the method names.

While the Python people aren't stopping to talk about the clearness of
their language, nothing is clear and explicit, when it comes to overloading
or metaclasses.

Anyway, IMHO, "class.__add__ = foo" or your example manipulating
"class.__dict__" (another special attribute name!) is the point, where
you can install Parrot semantics WRT method overloading.

> Now, given the above sample, let's revisit the statement that "The
> Python translator needs just a translation table for the common core
> methods."

We both know that's a simplification :) You've to install the methods of
course ...

> How, exactly, would that be done? Given that the method name is simply
> a string... used as a key in dictionary... with a different parameter
> signature than the hypothetical Parrot __add method.

The "class.__dict__" dictionary is special. Setting an "__add__" key too.
The combined meaning is overloading. The different signature is a
problem, yes - I've already mentioned that. And Parrot's "__add" method
is not hypothetical :-)

$ grep __add t/pmc/object*.t

> That's why I say:

>>>In the general case, looking for "reserved" method names at "compile"
>>>time doesn't work.

>> "__add__" is reserved in Python and corresponds directly to "__add" in
>> Parrot. I don't think that doesn't work.

> __add__ is *not* reserved in Python.

Does it matter if the name is actually reserved? The meaning is
important.

> ... There just is some syntatic sugar


> that provide a shorthand for certain signatures. I am free to define
> __add__ methods that have zero or sixteen arguments. I won't be able to
> call such methods with the convenient shorthand, but other than that,
> they should work.

I'd say, if you define an '__add__' method with 16 arguments, Python
will throw an exception, if you try to use C<+> with an object of that
class:

TypeError: myadd() takes exactly 16 arguments (2 given)

So that's rather hypothetical. And if you always use x."__add__"(16
args) Parrot will just run the function.

>>>I personally don't think that performance considerations should be out
>>>of bounds in these discussions
>>
>> I've already shown that it's possible to go with fully dynamic dispatch
>> *and* 30% faster for MMD and 70% faster for overloaded operations. First
>> correct and complete, then speed considerations.

> Neither of which match Python semantics. We are going to need a system
> where classes are anonymous, not global.

Why? And how do you find your class then:

c = C()
...
3 22 LOAD_NAME 1 (C)
25 CALL_FUNCTION 0

> ... Where methods are properties


> that can be added simply by calling the equivalent of set_pmc_keyed.

Nah. Methods aren't properties, but ...

The "set_pmc_keyed" on "__dict__" (or an equivalent setattribute call)
of your type system is responsible to create Parrot semantics for method
calls :-)

> - Sam Ruby

leo

Sam Ruby

unread,
Dec 8, 2004, 3:44:30 PM12/8/04
to l...@toetsch.at, perl6-i...@perl.org
Leopold Toetsch wrote:

> Sam Ruby <ru...@intertwingly.net> wrote:
>
>>Leopold Toetsch wrote:
>
>>Here's the part that you snipped that addresses that question:
>
>> > And there is a piece that I haven't written yet that will do the
>> > reverse: if MMD_ADD is called on a PyObject that has not provided
>> > such behavior, then an any __add__ method provided needs to be
>> > called.
>
> Ok. But that would imply that HLL interoperbility isn't really possible. Or
> just at a minimal surface level. But see below.

I don't believe that to be the case. If a Perl subroutine were to call
a Python function and pass a PerlInt as a parameter, the receiving
function should expect to be able to do addition via tha "+" operator,
but should not be expect to find an "__add__" method on such objects.
Instead, and if they cared to, they could explicitly call the "__add"
method provided.

The reverse should also be true, if Python function were to call a Perl
subroutine and pass a PyInt as a parameter, the receiving subroutine
should expect to be able to do addition via the "+" operator, but not
expect to find an "__add" method on such objects. Instead, and if they
cared to, they could explicitly call the "__add__" method provided.

I would consider that significant interoperability with only minimal
restrictions.

> While the Python people aren't stopping to talk about the clearness of
> their language, nothing is clear and explicit, when it comes to overloading
> or metaclasses.

Please don't do that. I am not trying to extoll the virtues of Python,
merely trying to implement it.

> Anyway, IMHO, "class.__add__ = foo" or your example manipulating
> "class.__dict__" (another special attribute name!) is the point, where
> you can install Parrot semantics WRT method overloading.

Hold that thought. I'll answer this below.

>>Now, given the above sample, let's revisit the statement that "The
>>Python translator needs just a translation table for the common core
>>methods."
>
> We both know that's a simplification :) You've to install the methods of
> course ...

Again, it can't be done exclusively at translation time. It needs to be
done at runtime. And if it is done at runtime, it need not be done at
translation time at all. More below.

>>How, exactly, would that be done? Given that the method name is simply
>>a string... used as a key in dictionary... with a different parameter
>>signature than the hypothetical Parrot __add method.
>
> The "class.__dict__" dictionary is special. Setting an "__add__" key too.
> The combined meaning is overloading. The different signature is a
> problem, yes - I've already mentioned that. And Parrot's "__add" method
> is not hypothetical :-)
>
> $ grep __add t/pmc/object*.t

Here I'll apologize for being unclear. Yes, there is code in the
existing object class in support of Perl's S06. What's hypothetical is
the presumption that all languages will adopt Perl 6's naming convention
for methods.

>>That's why I say:
>
>>>>In the general case, looking for "reserved" method names at "compile"
>>>>time doesn't work.
>
>>>"__add__" is reserved in Python and corresponds directly to "__add" in
>>>Parrot. I don't think that doesn't work.
>
>>__add__ is *not* reserved in Python.
>
> Does it matter if the name is actually reserved? The meaning is
> important.

It does matter. Python classes are dictionaries of objects, some of
which may be functions. You may extract objects from that dictionary
and access them later. The "meaning" in such a scenario is not apparent
until well after all interaction with the compile and runtime
dictionaries is over.

>>... There just is some syntatic sugar
>>that provide a shorthand for certain signatures. I am free to define
>>__add__ methods that have zero or sixteen arguments. I won't be able to
>>call such methods with the convenient shorthand, but other than that,
>>they should work.
>
> I'd say, if you define an '__add__' method with 16 arguments, Python
> will throw an exception, if you try to use C<+> with an object of that
> class:

If I define an __add__ method with 16 arguments, Python will not throw
an exception.

>>>I've already shown that it's possible to go with fully dynamic dispatch
>>>*and* 30% faster for MMD and 70% faster for overloaded operations. First
>>>correct and complete, then speed considerations.
>
>>Neither of which match Python semantics. We are going to need a system
>>where classes are anonymous, not global.
>
> Why? And how do you find your class then:
>
> c = C()
> ...
> 3 22 LOAD_NAME 1 (C)
> 25 CALL_FUNCTION 0

$pirate -d c.py
...
find_lex $P0, 'C'
$P1=$P0()
store_lex -1, 'c', $P1

The important part isn't simply in which hash a given class name is
looked up in, but that classes themselves in Python are transient
objects subject to garbage collection.

>>... Where methods are properties
>>that can be added simply by calling the equivalent of set_pmc_keyed.
>
> Nah. Methods aren't properties, but ...

No? Try the following:

x = "abcdef".find
print x('c')

> The "set_pmc_keyed" on "__dict__" (or an equivalent setattribute call)
> of your type system is responsible to create Parrot semantics for method
> calls :-)

If this is done at runtime, the it need not be done at compile time.

However, it doesn't stop here. Just like methods can be added
dynamically by name at runtime, they can be accessed dynamically by
name. That means that all method lookups will need to be preceeded by a
hash lookup. An not just on Python objects, but *all* objects.

That's why I object to characterizations like "dynamic dispatch is 30%
faster than...". What will ultimately result if it is mandated that all
languages adopt Perl6's semantics is that an ADDITIONAL dynamic dispatch
will be required to make non-Perl6 functions work.

- - -

The alternative is to treat C<__add> and C<__add__> as characterists
that some languages chose to place on their objects, and outside the
scope of the standard behaviors that Parrot provides. All such existing
behavior moves from src/objects.c and src/global.c and classes/*.pmc to
dynclass/perl*.pmc and/or dynclass/py*.pmc as appropriate.

Internally, Parrot will define a large but finite set of methods. One
pair of such methods, C<find_method> and <invoke> are provided for
languages to define their own behaviors. The namespaces for the two
sets of methods is purposefully kept separate.

PerlScalar's implementation of the add will know about how to implement
Perl 6's multi sub *infix. PyObject won't, but it will know about
Python's __meta__ and __init_class__.

Users of languages built on Parrot should expect things like C<+> and
C<[]> and iterators to work, but when they wander off into language
specific territory, they will need to utilize mechanisms based on
find_method and knowledge of names of the methods that they are trying
to call.

- Sam Ruby

Leopold Toetsch

unread,
Dec 8, 2004, 4:40:34 PM12/8/04
to Sam Ruby, perl6-i...@perl.org
Sam Ruby <ru...@intertwingly.net> wrote:

[ snipped - all ok }

> If I define an __add__ method with 16 arguments, Python will not throw
> an exception.

I didn't write that. I've said: *if* you call it via "a + b", Python
throws an exception - that one I've shown. Anyway...

> If this is done at runtime, the it need not be done at compile time.

... Yes. That's the overall conclusiom it seems. It can be done partially
at compile time, and it isn't worth the effort to try it, because
languages we are targeting are too dynamic.

> However, it doesn't stop here. Just like methods can be added
> dynamically by name at runtime, they can be accessed dynamically by
> name. That means that all method lookups will need to be preceeded by a
> hash lookup. An not just on Python objects, but *all* objects.

... preceeded by some kind of lookup, which is defined by
"class->vtable->find_method()" of the responsible metaclass. Being it
one or 100 hash lookups in properties, dicts, globals and what not. It
doesn't matter. Dot.

> That's why I object to characterizations like "dynamic dispatch is 30%
> faster than...". What will ultimately result if it is mandated that all
> languages adopt Perl6's semantics is that an ADDITIONAL dynamic dispatch
> will be required to make non-Perl6 functions work.

You are still not getting the principal of the scheme, IMHO. It has
nothing to do with Perl6 or any other language, nor with Python.

The original subject: "premature pessimization" strikes back :)

Whe just do a dynamic lookup at runtime - that's all.

The e.g. "add" opcode calls left->vtable->find_method(), and probably
more if the return results inidicates MMD. Eventually one of the
find_method calls returns a function that does implement the "__add"
method for the involved types. Or a (possibly user provided) distance
function decides, which function to call. It doesn't matter.

Then the *runcore* calls the function and *caches* the function pointer.

Next time the call is instantaneous, given that the language is able to
call a cache invalidation function, if method lookup order (for that
class) changes.

The call to the invalidation function is possible, even for Python.
*Iff* you can roll your own method dispatch, you eventually need to
know, which method you call. That has to be defined. You can as well
call a cache invalidation function, if something changes here (I hope)

> PerlScalar's implementation of the add will know about how to implement
> Perl 6's multi sub *infix. PyObject won't, but it will know about
> Python's __meta__ and __init_class__.

If even an "add" instruction doesn't work outside of one HLL, we can
forget any interoperbility. "__meta__" and what not Python semantics can
be added - or not :-) But let's first concentrate on the basics.

> - Sam Ruby

leo

Sam Ruby

unread,
Dec 8, 2004, 5:51:39 PM12/8/04
to l...@toetsch.at, perl6-i...@perl.org
Leopold Toetsch wrote:

> Sam Ruby <ru...@intertwingly.net> wrote:
>
> [ snipped - all ok }
>
>>If I define an __add__ method with 16 arguments, Python will not throw
>>an exception.
>
> I didn't write that. I've said: *if* you call it via "a + b", Python
> throws an exception - that one I've shown. Anyway...

What you wrote (and snipped) was

"I'd say, if you define an '__add__' method with 16 arguments, Python
will throw an exception,..."

To which I responded with the above.

> You are still not getting the principal of the scheme, IMHO. It has
> nothing to do with Perl6 or any other language, nor with Python.

Either that, or I *am* getting the principle of the scheme. I guess
that this is the point where I need to return back to writing code and
test cases.

Leo - at one point you indicated that you might be interested in helping
to factor out the common code again. Please feel free to do so whenever
you are ready. All I ask is that you don't break the test cases.

- Sam Ruby

P.S. No fair changing the test cases either. ;-)

Leopold Toetsch

unread,
Dec 9, 2004, 2:21:01 AM12/9/04
to Sam Ruby, perl6-i...@perl.org
Sam Ruby <ru...@intertwingly.net> wrote:
> Leopold Toetsch wrote:

>> Sam Ruby <ru...@intertwingly.net> wrote:
>>
>> [ snipped - all ok }
>>
>>>If I define an __add__ method with 16 arguments, Python will not throw
>>>an exception.
>>
>> I didn't write that. I've said: *if* you call it via "a + b", Python
>> throws an exception - that one I've shown. Anyway...

> What you wrote (and snipped) was

> "I'd say, if you define an '__add__' method with 16 arguments, Python
> will throw an exception,..."

> To which I responded with the above.

and after the snipped ellipsis my sentence did continue with

" if you try to use C<+> with an object of that class:"

>> You are still not getting the principal of the scheme, IMHO. It has


>> nothing to do with Perl6 or any other language, nor with Python.

> Either that, or I *am* getting the principle of the scheme. I guess
> that this is the point where I need to return back to writing code and
> test cases.

> Leo - at one point you indicated that you might be interested in helping
> to factor out the common code again.

Sure, and I'm not stopping that. The overall conclusion of (even infix
operator) method lookup was that it has to be done at runtime. It is up to
the PMCs to provide a proper and language-specific find_method to locate
the involved operation, MMD or not.

And the runcore is responsible for calling the method. While you seem to
admit that it has to be done at runtime you are doubting that it can be
done fast and you are rolling your own incompatible dispatch scheme (how
should that be faster then?). This made me utter above sentence.

Further: The function signature of overloaded infix operations (and
maybe others) is currently not appropriate for Python (and likely other
languages).

> - Sam Ruby

leo

Sam Ruby

unread,
Dec 9, 2004, 5:19:18 AM12/9/04
to l...@toetsch.at, perl6-i...@perl.org
Leopold Toetsch wrote:
>
>>Leo - at one point you indicated that you might be interested in helping
>>to factor out the common code again.
>
> Sure, and I'm not stopping that. The overall conclusion of (even infix
> operator) method lookup was that it has to be done at runtime. It is up to
> the PMCs to provide a proper and language-specific find_method to locate
> the involved operation, MMD or not.

I continue to disagree with the part of this conclusion where you insert
find_method into the discussion. To give a concrete example: at the
moment the lookup involved in abs_p_p does not involve the use of
find_method. Nor does the lookup involved in find_method_p_p_s for that
matter.

If Perl programmers need to know about Parrot method names, then
effectively this beomes part of the Perl language specification. I do
not have the luxury of changing the Python language specification.

I continue to push for the "namespace" for Parrot internal dispatching
and language level method names to be disjoint. If Python metaclasses
get surprising results if they happen to define a method named
"instantiate", expect a bug report. (BTW, a combined instantiate method
does not map well to Python which has separate __new__ and __init__
methods. You are going to find issues like these every time you try to
put object oriented semantics into the Parrot core. My recommendation
is to stick to primitives, and simply provide a new_p_p).

There needs to be separate "find_method" operations for external (i.e.,
visible at the language level) names and Parrot internal names.

> And the runcore is responsible for calling the method. While you seem to
> admit that it has to be done at runtime you are doubting that it can be
> done fast and you are rolling your own incompatible dispatch scheme (how
> should that be faster then?). This made me utter above sentence.

"as long as we have a proper protocol that everyone can conform to, we
should be OK." - Dan Sugalski, 2004/11/29

> Further: The function signature of overloaded infix operations (and
> maybe others) is currently not appropriate for Python (and likely other
> languages).

That is only because the design you have in mind conflates Parrot and
language operations. There is no reason that __abs__ couldn't call
VTABLE_abs, or that __add__ can't make use of MMD_ADD.

- Sam Ruby

Leopold Toetsch

unread,
Dec 9, 2004, 8:59:03 AM12/9/04
to Sam Ruby, perl6-i...@perl.org
Sam Ruby <ru...@intertwingly.net> wrote:

> I continue to disagree with the part of this conclusion where you insert
> find_method into the discussion. To give a concrete example: at the
> moment the lookup involved in abs_p_p does not involve the use of
> find_method.

$ cat abs.imc
.sub main
.local pmc cl, o
cl = newclass "A"
$I0 = typeof cl
o = new $I0
$P0 = new Undef
$P0 = abs o
print $P0
.end

.namespace ["A"]
.sub __absolute
.param pmc d
d = "ok\n"
.end

$ parrot abs.imc
ok

$ parrot -t abs.imc
...
# find_method class 'A' method '__absolute': Sub
# Calling sub '__absolute'
...

> ... Nor does the lookup involved in find_method_p_p_s for that
> matter.

???

> If Perl programmers need to know about Parrot method names, then
> effectively this beomes part of the Perl language specification. I do
> not have the luxury of changing the Python language specification.

If you are targeting Parrot you have to know the opcode names *and* the
reserved method names, sorry.

> I continue to push for the "namespace" for Parrot internal dispatching
> and language level method names to be disjoint.

That's a different thing that we can consider.

> ... If Python metaclasses


> get surprising results if they happen to define a method named
> "instantiate", expect a bug report.

Ok. The call syntax should rather be "__instantiate" to be consistent.

> ... (BTW, a combined instantiate method


> does not map well to Python which has separate __new__ and __init__
> methods.

We have the "__init" hook too. This is separate.

$ parrot -t abs.imc
...
6 new P17, I30 - P17=PMCNULL, I30=72
# find_method class 'A' method '__init': no

> ... My recommendation


> is to stick to primitives, and simply provide a new_p_p).

What is the second "_p" for?

> There needs to be separate "find_method" operations for external (i.e.,
> visible at the language level) names and Parrot internal names.

Maybe. But why is it necessary?

> That is only because the design you have in mind conflates Parrot and
> language operations. There is no reason that __abs__ couldn't call
> VTABLE_abs, or that __add__ can't make use of MMD_ADD.

And if the class implements it's own "__absolute" or "__add", we do a
separate redispatch? And dynclasses/py* does it differently to
dynclasses/perl*. Why don't you just believe me that that's error prone
and slow ;-)

> - Sam Ruby

leo

Sam Ruby

unread,
Dec 10, 2004, 6:25:08 AM12/10/04
to l...@toetsch.at, perl6-i...@perl.org
Leopold Toetsch wrote:

But only for classes that inherit from delegate.

>>If Perl programmers need to know about Parrot method names, then
>>effectively this beomes part of the Perl language specification. I do
>>not have the luxury of changing the Python language specification.
>
> If you are targeting Parrot you have to know the opcode names *and* the
> reserved method names, sorry.

People writing Python to Parrot translators need to know Parrot
internals. People who merely write in Python should not.

>>... (BTW, a combined instantiate method
>>does not map well to Python which has separate __new__ and __init__
>>methods.
>
> We have the "__init" hook too. This is separate.

Ultimately, I believe that this will need to be revisited.

> $ parrot -t abs.imc
> ...
> 6 new P17, I30 - P17=PMCNULL, I30=72
> # find_method class 'A' method '__init': no
>
>>... My recommendation
>>is to stick to primitives, and simply provide a new_p_p).
>
> What is the second "_p" for?

What I am thinking of is something like:

inline op new(out PMC) {
$1 = VTABLE_instantiate(interpreter, $2);
goto NEXT();
}

Where instantiate does not support a variable number of arguments
(Parrot calling conventions). If you then want to init the PMC you have
obtained, you can use the separate init hook (with a variable number of
arguments).

>>That is only because the design you have in mind conflates Parrot and
>>language operations. There is no reason that __abs__ couldn't call
>>VTABLE_abs, or that __add__ can't make use of MMD_ADD.
>
> And if the class implements it's own "__absolute" or "__add", we do a
> separate redispatch? And dynclasses/py* does it differently to
> dynclasses/perl*. Why don't you just believe me that that's error prone
> and slow ;-)

Only in the sense that CoRoutine and RetContinuation provide
"incompatible" (i.e., different) implementations of invoke. However,
they are very compatible in the only sense that matters: they both
implement the common protocol named "invoke".

Arguably, the very reason that a find_method VTABLE entry was provided
was to enable different PMCs to provide different implementations of
this protocol.

The code that backs perl classes can have implementations find_method
that looks for __add methods with a given parameter signature, and the
code that backs python classes can have implementations of find_metho
that looks for __add__ methods with a different parameter signature.

- Sam Ruby

Leopold Toetsch

unread,
Dec 10, 2004, 9:23:57 AM12/10/04
to Sam Ruby, perl6-i...@perl.org
Sam Ruby <ru...@intertwingly.net> wrote:
> Leopold Toetsch wrote:

>> # find_method class 'A' method '__absolute': Sub
>> # Calling sub '__absolute'

> But only for classes that inherit from delegate.

Yes of course. Objects's derived from ParrotObject (i.e. Parrot standard
objects) dispatch to overloaded functions via the meta-class helper
class "delegate". Standard PMCs call pmc->vtable->absolute().

But infix operations like the "add" opcode dispatch via mmd_dispatch_*
and have no delegate functionality.

I've posted a graphic of all these possibilities in one of the mails.

This is the reason why I'm prefering to replace all with just one
scheme that works, i.e. doing full dynamic dispatch at the opcode level.

> People writing Python to Parrot translators need to know Parrot
> internals. People who merely write in Python should not.

Why on earth should Python writers know Parrot internals? Why do you
come to such a conclusion?

>>>... (BTW, a combined instantiate method
>>>does not map well to Python which has separate __new__ and __init__
>>>methods.
>>
>> We have the "__init" hook too. This is separate.

> Ultimately, I believe that this will need to be revisited.

What is wrong? Does it not work?

>>>... My recommendation
>>>is to stick to primitives, and simply provide a new_p_p).
>>
>> What is the second "_p" for?

> What I am thinking of is something like:

> inline op new(out PMC) {
> $1 = VTABLE_instantiate(interpreter, $2);

There is no second argument on the "new" signature. But I presume it's a
class PMC. Well doing:

cl = getclass "Foo"
o = cl."instantiate"()

does exactly that - it constructs a new Integer with the default value by
calling pmc_new/init.

OTOH when you have

cl = getclass "Foo"
o = cl."instantiate"(5)

you have two possiblities: implement the "instantiate" vtable (or let a
user provided overridden method do the initialization) or do the init
stuff in "__init", which get's again the arguments according to pdd03.

> .... If you then want to init the PMC you have


> obtained, you can use the separate init hook (with a variable number of
> arguments).

This is working already.

.sub main
.local pmc cl, o

cl = subclass "Integer", "A"
o = cl."instantiate"(5)
print o
print "\n"
.end

.namespace ["A"]
.sub __init method
.param int i
self = i
.end

> The code that backs perl classes can have implementations find_method
> that looks for __add methods with a given parameter signature, and the
> code that backs python classes can have implementations of find_metho
> that looks for __add__ methods with a different parameter signature.

Sam, there *should* be no difference between a pythonic "__add__"
and Parrot's "__add". Currently calling conventions don't match - I've
posted a mail WRT this and it needs fixing.

And Perl doesn't have an "__add" or such. Perl5 has "use overload '+' =>
..." Perl6 has a special infix:<+> syntax.

So the prerequisit is that Parrot's function signature of overloaded
methods is appropriate for Python and Perl.

We have:

a = b + c

You already did show the Python code, which emits the Parrot opcode
"add", which does MMD dispatch. But we both posted an example that
overloads the operator "+" with a piece of user provided function.

You've stated that the code to provide this functionality is missing in
py*.pmc. But when you write it, you have of course to know, that a
setattribute (or a __dict__ update) with the key "__add__" is meaning an
overload of the "+" operator. Else you wouldn't be able to roll your own
dispatcher.

So when your translator encounters:

def myadd(self, r):
return self - r

class J(int):
__add__ = myadd

i = J(44)
print i, i + 2

you have to know that "myadd" will be the function that is called, when an
"add" operation for an object of class "J" is executed. This is the
place where you would call:

Parrot_store_global(interp, "J", "__add", myadd);

The subroutine PMC myadd is stored into the namespace of "J" as
the subroutine labeled "__add".

In the current system you would have to call "mmdvtregister" to
associate the "myadd" subroutine with the "add" opcode for the given
types - but that doesn't work for objects derived from class "J" nor for
mixed types.

So what I'm saying (or I'm trying to) is: when at the opcode level the
"add" opcode is actually acting as a method call, everything works as
now including dynamic overriding of MMD functions. And there is no need
at all for duplicating a lot of Parrot core functionality in the
py*.pmcs.

I've described that in "MMD dispatch". With the help of the inline cache
this scheme is 30% faster then the current static MMD table dispatch.

> - Sam Ruby

leo

0 new messages