Leopold Toetsch wrote:
> Sam Ruby wrote:
> 
>> Let me try again to move the discussion from subjective adjectives to
>> objective code.  Consider:
> 
> [ example code ]
> 
>> If you run this, you will get 1,2,3.
>>
>> When called as a function, f will return the value of the second
>> parameter.  When called as a method, the same code will need to return
>> the value of the first parameter.
> 
> The calls to f() work more or less w/o problems in branches/leo-ctx5.
> 
>> I'm open to suggestions as to what PIR code should be emitted by Pirate
>> to correspond to the above code.
> 
> A stripped down PIR-only, pythonless translation is below.

Thanks for doing this.  Keeping the conversation anchored with code is
very helpful.  I have a number of unimportant to the topic at hand
comments on that code (example: classes aren't global in Python), but
for now, I'll focus on comments that are relevant to the topic at hand.

>> The way this currently works with Pirate and the existing Py*.pmc
>> closely follows the Python definition, which you can find here:
>>
>> http://users.rcn.com/python/download/Descriptor.htm#functions-and-methods
> 
> Good explanation, thanks.
> 
>> To illustrate how this works today, lets consider the call to foo.f(2)
>> above.   This involves both a find_method and an invoke.  Lets consider
>> each in turn:
>>
>>  * pyclass.find_method first calls getprop on "f".
>>  * pyclass.find_method then calls "__get__" on the pyfunc returned,
>>    passing the object on which this method was called on.
>>  * pyfunc.__get__ creates a new PyBoundMeth object, saving both the
>>    original function and the object.
>>  * This PyBoundMeth object is then returned
>>
>> then:
>>
>>  * pyboundmeth.invoke shifts all registers right, inserts the original
>>    object as the first parameter, and then calls invoke on the original
>>    function.
>>
>> Needless to say, this doesn't necessarily show off Parrot to its best
>> advantage from a performance perspective.  I tried a number of times to
>> argue for a combined "find_and_invoke" VTABLE entry as much of the above
>> can be optimized if you know that result of the find_method will only be
>> used a single time for an invoke.  If you like, you can scan the
>> archives to see what reception this suggestion received.
> 
> Well I think that the find_and_invoke is just the callmethodcc opcode as
> used in my translation below. The call to __get__ and the BoundMethod
> shouldn't be necessary, *if* their is no userdefined descriptor. That
> is, when getattribute checks, if the attribute provides __get__ then
> call it.

Take a look at the definition of callmethodcc in ops/object.ops.  It is
a find_method followed by an invoke.  It is the VTABLE operations that I
would like to see combined.

Note that Python provides __get__ methods for you on every function and
method, i.e., it is *not* optional, getattribute will always succeed.
Observe:

[EMAIL PROTECTED]:~$ python
Python 2.4.1 (#2, Mar 30 2005, 21:51:10)
[GCC 3.3.5 (Debian 1:3.3.5-8ubuntu2)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> def f(): pass
...
>>> f.__get__
<method-wrapper object at 0xb7e0404c>
>>> class c:
...   def m(self): pass
...
>>> c.m.__get__
<method-wrapper object at 0xb7e0440c>
>>>

> The yet unsopported thing is
> 
>   g = foo.g
>   ...
>   g(3)
> 
> which really needs a BoundSub object. But this is just a special case of
> currying, or a special case of Perl6's .assuming(). Therefore I think
> that Parrot should support this natively.

I agree that BoundSub is a special case of currying, or what Perl6 calls
assuming.  I also agree that Parrot should support this natively.

>> - Sam Ruby

[snip]

Below is from the sample that Leo provided.

> #  print foo.f(2)
> 
>     # emulate python find_name, which checks attributes too
>     push_eh m_nf
>     $P0 = foo."f"(2)
>     clear_eh
>     goto m_f
> m_nf:
>     # getattribute would also check if __get__ is there
>     $P1 = getattribute foo, "f"
>     $P0 = foo.$P1(2)
> m_f:
>     print_item $P0
>     print_newline

Note that the code above would need to be emitted for *every* method
call, as there is no way of knowing at compile time what property you
will get and how it is defined.  In addition to increasing code size, it
is error prone: for example, the above only appears to check for __get__
if the call fails, so the pie-thon b0 test will fail as hooking __get__
is integral to the way it provides a trace.  Also, there are other
reasons that exceptions may be thrown, and we are incurring the overhead
of setting up exception blocks, etc.... again, this would apply to
*every* method call.

An alternate solution without these problems would be

> #  print foo.f(2)
>     $P0 = foo."f"(2)
>     print_item $P0
>     print_newline

Ideally, callmethodcc would result in one vtable call to enable
interesting optimizations for those that care to provide it.  The
default implementation for this vtable entry could be a call to
find_method and invoke.

- Sam Ruby

Reply via email to