On Nov 5, 2004, at 10:03 AM, Sam Ruby wrote:

Jeff Clites wrote:
a) As Sam says, in Python "y**z" is just shorthand for "y.__pow__(z)"--they will compile down to exactly the same thing (required for Python to behave correctly). Since __pow__ isn't "special", we don't need anything to support it that we wouldn't need for any other arbitrary method, say "y.elbowCanOpener(z)".

[snip]

So I don't think an op really gives us what we want. (Specifically, we could define a pow_p_p_p op, but then Python wouldn't use it for the case Sam brought up.) I'd apply the same argument to many of the other p_p_p ops that we have--they don't gives us what we need at the HLL level (though they may still be necessary for other uses).

It is my intent that Python *would* use this method. What is important isn't that y**z actually call y.__pow__(z), but that the two have the same effect.


Let's take a related example: y+z. I could make sure that each are PMCs

[Not really a need for a check--everything will be a PMC, right? Or if not, you need to know before emitting the op anyway. Side issue, though.]


and then find the __add__ attribute, retrieve it, and then use it as a basis for a subroutine call, as the semantics of Python would seem to require. Or I could simply emit the add op.

How do I make these the same? I have a common base class for all python objects which defines an __add__ method thus:

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

... so, people who invoke the __add__ method explicitly get the same function done, albeit at a marginally higher cost.

There are three problems I see with this:

1) If you have 2 PerlInts in Python code, then "a + b" will work, but "a.__add__(b)" won't, since PerlInts won't inherit from your Python base class. To my mind, that breaks an invariant of Python.

2) If your __add__ method above were somehow in place even for PerlInts, it would produce a PyObject as its result, instead of a PerlInt, which is what I would have expected. That's a basic problem with our p_p_p ops currently--the return type can't be decided by the implementation of the MMD method which is called.

and...

Now to complete this, what I plan to do is to also implement all MMD/vtable operations at the PyObject level and have them call the corresponding Python methods. This will enable user level __add__ methods to be called.

Prior to calling the method, there will need to be a check to ensure that the method to be called was, in fact, overridden. If not, a type_error exception will be thrown.

3) As described by Leo, the op would call the MMD dispatcher, which would ultimately do the method call, then your method above would call the MMD dispatcher, so you'd get an infinite loop, right? And if you avoid this by adding some check (as you mentioned) to make sure you only call __add__ if it was overridden (really, implemented at the user level), then your default implementation above will never be called, right?


If instead you just compile infix operators as method calls, then all of those problems go away, and it's much simpler conceptually and in terms of implementation.

And for Ruby (the language), it's explicit that infix operators are just an alternate syntax for method calls, so compiling them as ops is even more semantically problematic there.

JEff



Reply via email to