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

overloaded operator calling conventions

6 views
Skip to first unread message

Leopold Toetsch

unread,
Dec 9, 2004, 4:01:10 AM12/9/04
to Perl 6 Internals
A recent discussion with Sam has shown that the current calling
conventions for overloaded operators don't match Python semantics (nor
Perl6 when I interpret S06 and S13 correctly).

The difference is that Parrot is passing in the destination argument
while these languages are returning the operator result.

E.g.

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

class I(int):
__add__ = myadd

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

Parrot is expecting and calling a subroutine like:

.sub __add
.param left
.param right
.param dest
...
.end

and it's run in void context. This calling convention matches the "add"
opcode, where the destination argument has to exist. But it's not suited
for HLLs as the HLL compiler can't track the subroutine usage back to
overloading and adjust the emitted code.

A short-term solution would be to evaluate the return result (if the
function returns something) and assign that value to the "dest" argument.

Parrot would call

.sub __add
.param left
.param right
.param dest # HLL can use it or create a temp
...
.return(temp) # or .return (dest) if HLL knows about dest
.end

while this is still a bit sub-optimal because of the additional temp,
the HLL might create, it would at least match the semantics.

A more radical change would be to just adapt these opcodes to create an
appropriate PMC with the result.

Comments?
leo

Leopold Toetsch

unread,
Dec 11, 2004, 1:45:52 AM12/11/04
to Leopold Toetsch, perl6-i...@perl.org, d...@sidhe.org
Leopold Toetsch <l...@toetsch.at> wrote:

[ fullquote ]

> E.g.

> Parrot would call

Thinking more about that it seems that we don't have much chance to keep
the current scheme that the destination is passed in.

a Python snippet:

def myadd(self, r):
return I(self.v - r)

class I(object):
__add__ = myadd
def __init__(self, v):
self.v = v
def __repr__(self):
return "I(%d)" % self.v


i = I(44)
j = i + 2
k = j + 2
print i, j, k

The "add" opcode is overloaded and returns a new object of class "I".
The current scheme is:

$P0 = new Undef
$P0 = add i, 2

*If* the HLL compiler can somehow make a connection between the "myadd"
function as an overloaded "add" opcode, it could try to morph the passed
in destination argument. The whole morph code is bulky and slow,
changing one PMC into an arbitrary different one needs deallocating the
old one (what happens with finalizers?) and constructing a new one in
place.

But I doubt that a compiler can track such a usage (myadd could be in a
different file and imported). That means we are pre-constructing a LHS
PMC for nothing with all implications on GC and performance.

Second: looking at pmc.c:pmc_reuse() the code isn't able to and can't
never return a singleton as the result of an operation, because that
would mean to change the address of the argument, where only it's
pointer is passed.

> Comments?
> leo

leo

Sam Ruby

unread,
Dec 11, 2004, 9:29:38 AM12/11/04
to l...@toetsch.at, perl6-i...@perl.org, d...@sidhe.org
Leopold Toetsch wrote:
>
>>Comments?
>>leo

As enjoyable as this discussion has been, I'd like to ask that it be put
on hold for a few days. I've nearly got all the previously defined
languages/python/t/basic tests running, and once they are running, I'd
like to do a bit of refactoring and documentation of a complete proposal
on how this can work.

- Sam Ruby

P.S. Peeking at the current implementation may not be wise, as a number
of shortcuts were taken (example: int objects behave as their own class,
etc), which confuses the picture.

Dan Sugalski

unread,
Dec 13, 2004, 9:55:18 AM12/13/04
to l...@toetsch.at, perl6-i...@perl.org
At 7:45 AM +0100 12/11/04, Leopold Toetsch wrote:
>Thinking more about that it seems that we don't have much chance to keep
>the current scheme that the destination is passed in.

(This is probably out of order -- I've a lot of mail I'm backed up on
unfortunately, but since it was CC'd directly to me I'll take it)

The note here is that Parrot's MMD function signature for binary ops
doesn't match what Python needs. Parrot is:

void binary_mmd_op(pmc left, pmc right, pmc dest)

where Python is:

pmc dest = left.add(pmc right)

And, as you can see, the difference is more than just python creating
a destination where we require one to be passed in -- it's a method
call as well.

I fully expected this to be an issue. Perl 5 and perl 6 are going to
have different conventions, (and I think there may well be at least
two separate ones for perl 6, but I may be misrememebering) Ruby
doesn't match, and neither do any of the other languages. I think
there was some discussion back when this was first batted around, but
there might not have been.

The short answer here is to cope: that is, when installing an MMD
function, including one of the default MMD functions for a class, a
language needs to generate the appropriate wrapper function if
necessary to translate between what parrot provides and what the
language itself wants.

Nothing much for it -- no matter what we choose it's going to be
wrong for someone, so the sensible thing to do is choose the scheme
that works best for the underlying model (which we have) and leave it
to compilers and class libraries to translate to their own preferred
form. I think we're likely to find that the scheme we have catches on
reasonably well once we've hit release and start seeing widespread
use.
--
Dan

--------------------------------------it's like this-------------------
Dan Sugalski even samurai
d...@sidhe.org have teddy bears and even
teddy bears get drunk

Leopold Toetsch

unread,
Dec 14, 2004, 4:44:27 AM12/14/04
to Dan Sugalski, perl6-i...@perl.org
Dan Sugalski <d...@sidhe.org> wrote:
> At 7:45 AM +0100 12/11/04, Leopold Toetsch wrote:
>>Thinking more about that it seems that we don't have much chance to keep
>>the current scheme that the destination is passed in.

> I fully expected this to be an issue. Perl 5 and perl 6 are going to


> have different conventions, (and I think there may well be at least
> two separate ones for perl 6, but I may be misrememebering) Ruby
> doesn't match, and neither do any of the other languages.

[ ... ]

> Nothing much for it -- no matter what we choose it's going to be
> wrong for someone, so the sensible thing to do is choose the scheme
> that works best for the underlying model (which we have) and leave it
> to compilers and class libraries to translate to their own preferred
> form. I think we're likely to find that the scheme we have catches on
> reasonably well once we've hit release and start seeing widespread
> use.

Shouldn't the underlying model be at least near the expectations of HLLs
we want to support? It doesn't buy us anything, if we force all
languages to create wrappers. And "works best for the underlying model"
just means the code exists.

Finally the current implementation can't handle singletons (like PyNone) as
a return result from such opcodes.

leo

Leopold Toetsch

unread,
Dec 15, 2004, 8:31:34 AM12/15/04
to Dan Sugalski, perl6-i...@perl.org
Dan Sugalski <d...@sidhe.org> wrote:

> The note here is that Parrot's MMD function signature for binary ops
> doesn't match what Python needs. Parrot is:

> void binary_mmd_op(pmc left, pmc right, pmc dest)

> where Python is:

> pmc dest = left.add(pmc right)

Perl6 allows (according to S06) for calling a multi method:

mulit sub f($a, $b: $c) { ... }

function call syntax:

f($x, $y, $z);

as well as method call syntax on the first invocant:

$x.f($y, $z);

Perl5 as well as Python have the invocant as the first function
argument.

We could now of course translate at runtime between these call schemes
(prepend P2 and shift all up or move P5 into current_object and shift
arguments down). But this takes some time.

Why do we have the special notion of current_object in the first place?
Why not just pass all in as P5, P6, ...?

leo

Luke Palmer

unread,
Dec 15, 2004, 1:07:53 PM12/15/04
to Leopold Toetsch, Dan Sugalski, perl6-i...@perl.org
Leopold Toetsch writes:
> Why do we have the special notion of current_object in the first place?
> Why not just pass all in as P5, P6, ...?

I agree that this is the way to go. Especially if we have some marker
somewhere that tells us that we were called as a method.

Luke

Leopold Toetsch

unread,
Dec 16, 2004, 1:39:32 AM12/16/04
to Luke Palmer, perl6-i...@perl.org, d...@sidhe.org

Does the Perl6 compiler know function signatures at compile time?
S06 states: "Passing two many or too few invocants is a fatal error."
For a runtime check we'd need additionally the MMD object count.

> Luke

leo

Leopold Toetsch

unread,
Dec 16, 2004, 9:28:21 AM12/16/04
to Sam Ruby, perl6-i...@perl.org
Sam Ruby wrote:
>
> A few observations, first from an Parrot Internal perspective... in
> general, the code for the opcodes tend to do things like the following:
>
> $1->vtable->get_string(interpreter, $1)
>
> Note that the object tends to be repeated as the first argument. It
> often the case that the first argument matches the object on which the
> dispatch is based, but it is not necessarily so. In particular, these
> two values will be different whenever the implementation of a method
> wants to invoke the equivalent of SUPER(args).

Not quite. That'll be

class_self."__super"(args)

so again the invocant is the first argument after interpreter.

leo

Sam Ruby

unread,
Dec 16, 2004, 9:52:51 AM12/16/04
to Leopold Toetsch, perl6-i...@perl.org
Leopold Toetsch wrote:

Believe it or not, I think we are agreeing.

To invoke a method on an object using Parrot Calling Conventions, P2
needs to be the object used for dispatch purposes, and P5 needs to be
the actual object. In many cases, they will be the same, but in some
cases they will differ.

This isn't obvious from PDD03, but a simple clarification would take
care of that.

- Sam Ruby

Leopold Toetsch

unread,
Dec 16, 2004, 10:32:25 AM12/16/04
to Sam Ruby, perl6-i...@perl.org
Sam Ruby wrote:

>
> Leopold Toetsch wrote:
>>
>> class_self."__super"(args)
>>
>> so again the invocant is the first argument after interpreter.
>
>
> Believe it or not, I think we are agreeing.

*g*

> To invoke a method on an object using Parrot Calling Conventions, P2
> needs to be the object used for dispatch purposes, and P5 needs to be
> the actual object. In many cases, they will be the same, but in some
> cases they will differ.

Yep. Another good reason to pass the object as P5 (too).

> This isn't obvious from PDD03, but a simple clarification would take
> care of that.

I'm still waiting for Dan's decision.

> - Sam Ruby

leo

0 new messages