Dan Sugalski wrote:

At 5:04 PM -0500 1/18/05, Sam Ruby wrote:

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.

Mmm, syntax! :) Luckily it makes no difference to us at the parrot level. What that should translate to is something like:


    $P0 = find_method Parrot_string, "find"
     # Elided check for failed lookup and fallback to attribute fetch
    $P1 = make_bound_method(Parrot_string, $P0)
    $P1("r")

This will be a recurring theme in my replies. Any thing which presumes a bit of knowledge "at compile time" will ultimately not work.


Consider the following:

  class c:
    find = 7

  def f(x):
    return x.find

  print f(c())
  print f("Parrot")("r")

Now, what should the code for function f look like? The only reasonable answer is something along the lines of:

  getattribute $P0, P5, 'find'

This has to work.  In both of the two calls to f().

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.

While a good idea, I think it's not the right way to handle this. Binding objects to methods to create invokable subs is going to be something we're going to need for a lot of the languages, so I think we'd be better served providing a general facility to do it rather than leaving it to each individual language designer to do it. Should save some work all around too.

This would not be necessary, but the current implementation of the callmethodcc opcode unfortunately decouples the find_method (which is subject to the "not at compile time" restrictions alluded to above), and invoke. If these weren't decoupled (i.e., there was a VTABLE_find_method or equivalent entry), then this would not be necessary.


Static methods differ in that the object is not passed.

How is this different from a subroutine, then?

From a callee-perspective: not at all.

What is important to note is that from a caller-perspective, they will invoke such "subroutines" with the callmethcc opcode.

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

I'm assuming this is different from just a method on the class somehow?

From a callee perspective, this appears to be a method on the instance.

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

This is the part I'm not so sure about. It looks like, rather than having two sides (caller and calle) we have three, caller, callee, and the code that fetches the invokable in the first place.


I fully agree that the caller shouldn't know about this stuff, since it may well have been handed the invokable thing as part of a function call or pulled it out of a variable or something.

I don't think the callee should have to know anything special here, though -- it doesn't seem at all unreasonable to have the callee *not* have to do anything special, nor play any magic games. (And I think I'd be a bit peeved if I was writing code which passed in object A as the object being invoked on, but the method decided it wanted to use object B instead) This is especially true in a mixed-language environment when you've got a class with methods written in different languages -- setting up any conventions that'll actually be followed seems like an exercise in futility. :)

Perhaps you might not find Python to your liking. That's OK.

But the more general question is whether or not Parrot will implement the above as a policy, and thereby preclude langages like Python from being implemented on top of Parrot.

That leaves the code that actually fetches the invokable thing in the first place, and that seems like the right place for this to happen. The language the code is written in knows what should happen based on what it gets back when querying the object, so as long as we provide a standard means to do all the binding stuff, we shoul dbe fine.

I'm not sure what you mean by "the code that actually fetches the invokable thing" in this instance. If you mean an "at compile time" translation approach like you alluded above, then that won't work.


If you mean the callee (which after all, also matches this definition), you have a workable system. Perhaps one that is not to your taste, but workable.

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).

Right. There's going to be one generic method-not-found exception -- there really has to be only one, otherwise we're going to run into all sorts of cross-language problems. Exception unification (and, more likely, aliasing) is going to be one of the tricky issues.

Perhaps I am reading you incorrectly. Is what you are saying that all languages have to change if they wish to be implemented on top of Parrot?


As you might recall, I was involved in the ECMA CLI standardization. What I would like to avoid is something like the following:

http://vb.mvps.org/vfred/Trust.asp

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.

The one thing that leaving it in the interpreter structure and not explicitly passing it in gets us is we get notice if its actually extracted and used. Which is going to be fairly common, so I'm not sure what it buys us. I think we'll leave things as-is, but I'm not sure for how much longer.

Cool. Expect the majority of Python methods to reference "self".

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.

That can't happen. find_method has to return an unbound method, since there are just too many cases where that's what we need. If the method then needs to be bound then the fetching code can do the binding.

I think that it doesn't make sense for us to discuss this in abstract. Specific examples, like the one I provided above, and ones that I can extract from pie-thon do tend to lead to a different conclusion.


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).

I think we can make this work without any C stack nesting, if we make binding a primitive operation, which seems the sensible thing to do. fetch_method may well trigger bytecode, and there's nothing to be done about that regardless, but the rest should work out fine.

I've got most of pie-thon running. Patches welcome.

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.

Alas, with continuations there's never a guarantee of 'only once'. :(

If this is inside of "invoke", then the invokee knows whether or not it is a continuation. And if the entire "sequence" is repeated, then we are OK too. The problem is when find_method and invoke are decoupled.


*shrug*

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

Not planning on going this year.

I do plan on presenting on this topic at OSCON. I do expect the outcome to be quite different.


- Sam Ruby

Reply via email to