Dan Sugalski wrote:

Hi folks.

Welcome back!

Parrot's got the interesting, and somewhat unfortunate, requirement of having to allow all subroutines behave as methods and all methods behave as subroutines. (This is a perl 5 thing, but we have to make it work) That is, an invokable PMC may be invoked as a method call and passed in an object, or as a plain subroutine and not have an object passed in. As far as perl 5 is concerned the object is the first parameter in the argument list, but for everyone else the object is a very distinct and separate thing.

Python essentially has the same requirement, with a few twists. Specifically, methods come in be static, class, and regular flavors.


But first, a simple example. Strings in python have a "find" method, so and can do the following:

    f = "Parrot".find
    print f("r")

Note that I referenced the method as an attribute, and then called it as a function. Furthermore, the function "remembers" what object it is bound to. This is accomplished by VTABLE_find_method creating a new PyBoundMeth PMC which contains two references, one to the object, and one to the method. The sole responsibility of a bound method is to insert the first parameter into the call, and then to invoke the desired method.

Static methods differ in that the object is not passed.

Class methods differ in that the object passed is actually the class of the object in question.

Note: all this is determined by the callee. It is all transparent to the caller.

Now, compare that to callmethod or callmethodcc in ops:

   object = REG_PMC(2);
   method_pmc = VTABLE_find_method(interpreter, object, REG_STR(0));
   if (!method_pmc) {
     real_exception(interpreter, next, METH_NOT_FOUND,
         "Method '%Ss' not found", REG_STR(0));
   }
   REG_PMC(0) = method_pmc;
   interpreter->ctx.current_object = object;
   dest = (opcode_t *)VTABLE_invoke(interpreter, method_pmc, next);

First, observe that I don't have any control over the exception that is raised when a method is not found (fix: raise the exception within find_method). Second, observe that this assumes that current object is the object in all cases. This doesn't work well for static or class methods (fix: create a PyBoundMeth object which overrides this, and then call the real method).

This does make things a little tricker for the perl 5 code generator, but not that much trickier and, let's face it, we're below the layer where things are easy. This *also* makes building signature checking into parrot a lot simpler (something we should do), since the signature checking stuff doesn't have to deal with possible parameter shifting based on whether we've a sub or method invocation.

Parameter shifting actually is made easier by placing the object in question in a separate register... no shifting is required. (Note: in cvs, I actually do the shifting, partially because I'm in the process of reverting a change, and partially do to the issue raised in the next paragraph).


My one minor request here is P2 be made available on entry to the invoked method. This would remove some special case logic for me requiring the use of interpinfo. I don't expect any guarantees that this is preserved or restored across sub calls.

Not having objects handle their own method dispatch is less clear-cut, but I do have some reasons, so here they are.

Just be aware that in order to preserve Python semantics, find_method will need to return a bound method. This involves creating an object on the heap, garbage collection, and a minor addition to the number of instructions executed on invoke (including a nested C stack).


This could all be avoided if there was a VTABLE_callmethod interface as the code would "know" that the intent was to only use this found method exactly once.

*shrug*

Do you plan to choose banana cream again at OSCON 2005?

- Sam Ruby

Reply via email to