Re: Python PMC's

2005-08-24 Thread Sam Ruby
Leopold Toetsch wrote:
> 
> Above Parrot interface function tries to locate Sub objects in the
> namespace of the invocant's class and in the MRO of it. When you go back
> to the PIR translation of your code there is e.g.
> 
>   class Foo:
> def g(self,y):
> 
> I have translated this to:
> 
> .namespace ["Foo"]
> .sub g
> .param pmc self
> 
> Therefore all the static / default / common "methods" inside Python code
> would be callable with the plain Parrot method call syntax.
> 
> The classname contributes the namespace. The sub declaration creates an
> entry in that namespace, which is retrievable as:
> 
>   func = findglobal "Foo", "g"

Honestly, I don't believe that that is workable for Python.  Modules are
global in Python.  Classes are lexically scoped.  All subs emitted by
Pirate are @anon.

Modules are namespaces and can contain classes, functions, and
variables.  The way to retrieve a method from a Python class defined in
module __main__ would be:

  $P1 = findglobal "__main__", "Foo"
  getattribute $P2, $P1, 'g'

- Sam Ruby


Re: [pirate] Re: Python PMC's

2005-08-24 Thread Michal Wallace
On Wed, 24 Aug 2005, Sam Ruby wrote:

[huge cut]
 
> 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.


Hey Sam,

I agree with what you're saying in this
thread. This is slightly off topic, but
I wanted to point something out.

In general, python has so many places
where things have to be dynamic that you 
really can't know this kind of thing at 
compile time, especially if you allow for 
eval/exec, or if you allow the code to be 
used as a module. 

However if you treat the code as a closed 
system, *and* you have access to python at 
compile time, then we can optimize away a 
lot of these questions.

For example, in your original code:

  def f(x,y):
return y

  class Foo:
f = f
def g(self,y):
  return y

  foo = Foo()

  g=foo.g

  print f(0,1)
  print foo.f(2)
  print g(3)


Once you know how python works, it's *obvious* 
that this prints 1,2,3. I see no reason why the 
compiler couldn't figure this out up front just 
by walking the tree.

In fact, a good optimizing compiler would see the
"return y" lines and just get rid of those methods
completely. 

I'd like to allow for the ability to do certain 
optimizations like this up front, sacrificing 
flexibility for speed. I know there are many
programs that won't allow for this, but for the
ones that do, I'd like to be able to do a sort
of static compile like this. 

In other words, sometimes a python-like language
is a desirable thing. (But of course this should
all be optional so that we can also be 100%
python compatible)

Sincerely,
 
Michal J Wallace
Sabren Enterprises, Inc.
-
contact: [EMAIL PROTECTED]
hosting: http://www.cornerhost.com/
my site: http://www.withoutane.com/
-



Re: Python PMC's

2005-08-24 Thread Leopold Toetsch


On Aug 24, 2005, at 23:34, Sam Ruby wrote:



Leopold Toetsch wrote:



Note that you would then be caching the results of a curried function
call.  This result depends not only on the method string, but also on
the particular object upon which it was invoked.


No the "inner" Parrot_find_method_with_cache just caches the method 
for

a specific class (obeying C3 method resolution order as in Python).
There is no curried function at that stage.


Where does Parrot_find_method_with_cache get this data?

Remember, in Python, there are no methods, there are only properties.


Above Parrot interface function tries to locate Sub objects in the 
namespace of the invocant's class and in the MRO of it. When you go 
back to the PIR translation of your code there is e.g.


  class Foo:
def g(self,y):

I have translated this to:

.namespace ["Foo"]
.sub g
.param pmc self

Therefore all the static / default / common "methods" inside Python 
code would be callable with the plain Parrot method call syntax.


The classname contributes the namespace. The sub declaration creates an 
entry in that namespace, which is retrievable as:


  func = findglobal "Foo", "g"

And as the namespace is exactly the classname this is exactly what 
find_method for a "Foo" object does, when trying to locate a method 
named "g" (I'm omitting here further lookups according to MRO due to 
other parents). The actual namespace that the classes find_method looks 
into can further be finetuned with the vtable function 
VTABLE_namespace_name(interp, class).


Other methods, like the one defined by "f = f", would of course need a 
fallback to attribute lookup (please can we keep the term attribute, 
which is also used in CPython) - and not property). Therefore the 
'find_method' inside Py code should also consult the attributes of the 
object (and yes properties for per object overrides).


Well, this is at least my understanding how it could work.



Of course, there is a find_method VTABLE entry, and the implementation
of this function calls __get__ which performs the curry function, per
the Python specifications.


Yes. But currying isn't needed for a plain method call, when the 
__get__ isn't user defined. Why first curry the function in the first 
place, create a new curried sub PMC, then during invocation shift 
arguments, and eventually run it. This isn't the common case. Even if 
CPython does it like this now (and Python folks are discussing an 
optimized opcode on pthon-dev), it's not better or more correct - just 
the result is important. And that works as is now for Parrot method 
calls.




Does Parrot_find_method_with_cache cache the results of the previous
call to find_method?


It does one dynamic lookup and caches per class/method the result. The 
cache is invalidated by a store_global (which could influence the 
dynamic search result).



- Sam Ruby


leo



Re: Python PMC's

2005-08-24 Thread Sam Ruby
Leopold Toetsch wrote:
> 
>> Note that you would then be caching the results of a curried function
>> call.  This result depends not only on the method string, but also on
>> the particular object upon which it was invoked.
> 
> No the "inner" Parrot_find_method_with_cache just caches the method for
> a specific class (obeying C3 method resolution order as in Python).
> There is no curried function at that stage.

Where does Parrot_find_method_with_cache get this data?

Remember, in Python, there are no methods, there are only properties.

Of course, there is a find_method VTABLE entry, and the implementation
of this function calls __get__ which performs the curry function, per
the Python specifications.

Does Parrot_find_method_with_cache cache the results of the previous
call to find_method?

- Sam Ruby


Re: Python PMC's

2005-08-24 Thread Leopold Toetsch


On Aug 24, 2005, at 19:45, Sam Ruby wrote:



Leopold Toetsch wrote:

Sam Ruby wrote:





The return value is a callable sub.


More precisely: a curried function call.  This is an important
distinction; to see why, see below.


A callable sub may be of course a curried one - yes.


The interesting optimizations are:
- cache the find_method in the global method cache.
  This happens already, if the method string is constant.


Note that you would then be caching the results of a curried function
call.  This result depends not only on the method string, but also on
the particular object upon which it was invoked.


No the "inner" Parrot_find_method_with_cache just caches the method for 
a specific class (obeying C3 method resolution order as in Python). 
There is no curried function at that stage.





- use a PIC [1] (which is tied to the opcode) and cache
  the final resut of find_method (or any similar lookup)


Again, the results will depends on the object.


Yes. The nice thing with a PIC is that it is per bytecode location. You 
have a different PIC and a different cache for every call site. The 
prologue of PIC opcode is basically:


  if cache.version == interpreter.version:
 (cache.function)(args)
  else:
 # do dynamic lookup
 # update cache then repeat

The 'version' compare depends on the cached thingy, and is more 
explicit in individual implementations. But the principle remains 
always the same: you create a unique id that depends on the variables 
of the lookup and remember it. Before invoking the cached result you 
compare actual with cached ids. If there is a cache miss, there are 2 
or 3 more cache slots to consult before doing just the dynamic original 
scheme again (and maybe rewrite the opcode again to just the dynamic 
one in case of too many cache misses).


src/pic.c and ops/pic.ops have an implementation for sub Px, Py - just 
for fun and profit to show the performance in the MOPS benchmark ;-)


The important part in ops/pic.ops is:

lr_types = (left->vtable->base_type << 16) | 
right->vtable->base_type;

if (lru->lr_type == lr_types) {
runit_v_pp:
((mmd_f_v_pp)lru->f.real_function)(interpreter, left, right);

(the lru is part of the cache structure, above code will be only run, 
when both types are <= 0x)


MMD depends on the two involved types. This is compared before calling 
the cached function directly. As the cache is per bytecode location, 
there is a fair chance (>95 %) that the involved types for this very 
code location are matching.


The same is true for plain method calls. The callee depends on the 
invocant and the method name, which is usually a constant. Therefore 
you can compare the cached version with the actual invocant type and 
normally, with a match, just run the cached function immediately.


Currying is only important for placing the 'self' into the arguments - 
the actual lookup was already done earlier and doesn't influence the 
called function. Actually a curried subroutine isa 'Sub' object already 
and invoked directly withouth any further method lookup. There is no 
caching involved in the call of a curried sub.





- run the invoked Sub inside the same run loop - specifically
  not within Parrot_run_meth_fromc_args


I don't understand this.  (Note: it may not be important to this
discussion that I do understand this - all that is important to me is
that it works, and somehow I doubt that Parrot_run_meth_fromc_args 
cares

whether a given function is curried or not).


There are two points to be considered:
- currying: the effect is that some call arguments (in this special 
case the object) are already fixed. The argument passing code has 
therefore the duty to insert these known (and remembered) arguments 
into the params for the callee. For the BoundMethod this is of course, 
shift all arguments up by one, and make the object 'self' the first 
param of he sub.
- the second point is only related to call speed aka optimization. It's 
just faster to run a PIR sub in the same run loop, then to create a new 
run loop.



The above works because PyInt is a constant.  It probably can be
extended to handle things that seem unlikely to change very rapidly.


Yes. That's the 'trick' behind PIC. It works best the more constant the 
items are. But as said above, method names and invocants usually don't 
vary *per byecode location*. Literature states ~95 % of method calls 
are monomorphic (one type of invocant), and 99,5 % are cached within 4 
cache slots. Look at some typical code


   a.'foo'(x)
   ...
   b.'bar'(y)

Both method calls have a distinct cache. The method names are constant. 
Therefore the callee depends only on the invocant. The types of 'a' or 
'b' are typically the same (except maybe inside compilers AST visit 
methods or some such). The same schme applies to plain method or 
attribute lookups.



But the combination of decisions on how to handle the passing of the
"self" parameter to a method, keeping find_

Re: Python PMC's

2005-08-24 Thread Sam Ruby
Leopold Toetsch wrote:
> Sam Ruby wrote:
> 
>> Leopold Toetsch wrote:
> 
>>> A stripped down PIR-only, pythonless translation is below.
> 
>>   (example: classes aren't global in Python),
> 
> Yes, of course. The stripped down means essential the absence of any
> lexical handlings. But as you say, this doesn't matter for these sub and
> method calls.

Agreed.

>> Note that Python provides __get__ methods for you on every function and
>> method, i.e., it is *not* optional, getattribute will always succeed.
> 
> That's fine. But if it's not overriden by user code, you exactly know
> what it is doing. Therefore you can just emulate it, I think.

I'm not as sure as you appear to be, but we can worry about this later.

>>> #  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:
> 
>> Note that the code above would need to be emitted for *every* method
>> call, 
> 
> Above snippet should not be emitted for a method call, it just emulates
> it in PIR. It should demonstrate how Python's find_method() could be
> implemented:

With that clarification, I agree in principle.

> - try to find a method, else
> - check attributes
> - call __get__, if it is user provided
> 
> (or whatever order CPython actually uses).

What's in dynclass/pyclass.pmc matches Python's semantics closer.

> The return value is a callable sub.

More precisely: a curried function call.  This is an important
distinction; to see why, see below.

>> 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.
> 
> The interesting optimizations are:
> - cache the find_method in the global method cache.
>   This happens already, if the method string is constant.

Note that you would then be caching the results of a curried function
call.  This result depends not only on the method string, but also on
the particular object upon which it was invoked.

> - use a PIC [1] (which is tied to the opcode) and cache
>   the final resut of find_method (or any similar lookup)

Again, the results will depends on the object.

> - run the invoked Sub inside the same run loop - specifically
>   not within Parrot_run_meth_fromc_args

I don't understand this.  (Note: it may not be important to this
discussion that I do understand this - all that is important to me is
that it works, and somehow I doubt that Parrot_run_meth_fromc_args cares
whether a given function is curried or not).

> [1] polymorphic inline cache
> 
> The important thing is that the method lookup and the subroutine
> invocation happens from inside the runloop. Run cores that allow
> rewriting of opcodes (prederefed and JIT) can insert faster equivalent
> opcodes in these cases.
> 
> Have a look at src/pic.c (which doesn't implement a lot - it's more a
> proof of concept now). Anyway here is an example that is implemented:
> 
>   new P0, "PyInt"# new_p_sc
> 
> When this opcodes gets execute the first time, the type number of the
> class is looked up and then the opcode is replaced with the faster variant:
> 
>   new P0, 89 # new_p_ic  - arbitrary number for PyInt
> 
> The same scheme can be applied for all these opcodes that consist of any
> kind of a lookup (MMD, methods, attributes, ...) and some further
> action. The lookup is done once at runtime (and again only after cache
> invalidation).

The above works because PyInt is a constant.  It probably can be
extended to handle things that seem unlikely to change very rapidly.

But the combination of decisions on how to handle the passing of the
"self" parameter to a method, keeping find_method and invoke separated
at the VTABLE level, and the semantics of Python make the notion of
caching the results of find_method problematic.

>> - Sam Ruby
> 
> leo

- Sam Ruby


Re: Python PMC's

2005-08-24 Thread Leopold Toetsch

Sam Ruby wrote:

Leopold Toetsch wrote:



A stripped down PIR-only, pythonless translation is below.



  (example: classes aren't global in Python),


Yes, of course. The stripped down means essential the absence of any 
lexical handlings. But as you say, this doesn't matter for these sub and 
method calls.



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


That's fine. But if it's not overriden by user code, you exactly know 
what it is doing. Therefore you can just emulate it, I think.



#  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:



Note that the code above would need to be emitted for *every* method
call, 


Above snippet should not be emitted for a method call, it just emulates 
it in PIR. It should demonstrate how Python's find_method() could be 
implemented:


- try to find a method, else
- check attributes
- call __get__, if it is user provided

(or whatever order CPython actually uses).

The return value is a callable sub.


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.


The interesting optimizations are:
- cache the find_method in the global method cache.
  This happens already, if the method string is constant.
- use a PIC [1] (which is tied to the opcode) and cache
  the final resut of find_method (or any similar lookup)
- run the invoked Sub inside the same run loop - specifically
  not within Parrot_run_meth_fromc_args

[1] polymorphic inline cache

The important thing is that the method lookup and the subroutine 
invocation happens from inside the runloop. Run cores that allow 
rewriting of opcodes (prederefed and JIT) can insert faster equivalent 
opcodes in these cases.


Have a look at src/pic.c (which doesn't implement a lot - it's more a 
proof of concept now). Anyway here is an example that is implemented:


  new P0, "PyInt"# new_p_sc

When this opcodes gets execute the first time, the type number of the 
class is looked up and then the opcode is replaced with the faster variant:


  new P0, 89 # new_p_ic  - arbitrary number for PyInt

The same scheme can be applied for all these opcodes that consist of any 
kind of a lookup (MMD, methods, attributes, ...) and some further 
action. The lookup is done once at runtime (and again only after cache 
invalidation).



- Sam Ruby


leo



Re: [pirate] Re: Python PMC's

2005-08-24 Thread Kevin Tew
I agree this following would be cool.
However in the general case this type of code inference is HARD to do.
I believe that the optimizations you are looking for would require a
combination of type inference and graph reduction.
PyPy may be the eventual answer.
Don't get me wrong, I think it is great and the long term goal.
As soon as we compile and run correctly, I'm all about optimizations.

Good Insight Michal,
Kevin,

Michal Wallace wrote:
> Hey Sam,
>I agree with what you're saying in this
>thread. This is slightly off topic, but
>I wanted to point something out.
>
>In general, python has so many places
>where things have to be dynamic that you 
>really can't know this kind of thing at 
>compile time, especially if you allow for 
>eval/exec, or if you allow the code to be 
>used as a module. 
>
>However if you treat the code as a closed 
>system, *and* you have access to python at 
>compile time, then we can optimize away a 
>lot of these questions.
>
>For example, in your original code:
>
>  def f(x,y):
>return y
>
>  class Foo:
>f = f
>def g(self,y):
>  return y
>
>  foo = Foo()
>
>  g=foo.g
>
>  print f(0,1)
>  print foo.f(2)
>  print g(3)
>
>
>Once you know how python works, it's *obvious* 
>that this prints 1,2,3. I see no reason why the 
>compiler couldn't figure this out up front just 
>by walking the tree.
>
>In fact, a good optimizing compiler would see the
>"return y" lines and just get rid of those methods
>completely. 
>
>I'd like to allow for the ability to do certain 
>optimizations like this up front, sacrificing 
>flexibility for speed. I know there are many
>programs that won't allow for this, but for the
>ones that do, I'd like to be able to do a sort
>of static compile like this. 
>
>In other words, sometimes a python-like language
>is a desirable thing. (But of course this should
>all be optional so that we can also be 100%
>python compatible)
>
>Sincerely,
> 
>Michal J Wallace
>Sabren Enterprises, Inc.
>-
>contact: [EMAIL PROTECTED]
>hosting: http://www.cornerhost.com/
>my site: http://www.withoutane.com/
>-
>
>___
>pirate mailing list
>[EMAIL PROTECTED]
>http://cornerhost.com/mailman/listinfo/pirate
>  



Re: Python PMC's

2005-08-24 Thread Sam Ruby
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__

>>> class c:
...   def m(self): pass
...
>>> c.m.__get__

>>>

> 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


Re: Python PMC's

2005-08-24 Thread Leopold Toetsch

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.


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.


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.



- Sam Ruby


leo
#
#  def f(x,y):
#return y

.sub f
.param pmc x
.param pmc y
.return (y)
.end

#
#  class Foo:
.sub create_Foo
.local pmc self, Foo
self = subclass "Py", "Foo"
addattribute self, "f"
addattribute self, "g"
Foo = find_global "Foo", "Foo"
store_global "Foo", Foo
.end

.namespace ["Foo"]

.sub Foo
.local pmc o
o = new "Foo"
.return (o)
.end

#f = f
#def g(self,y):
#  return y

.sub __init method
.local pmc f, g
f = find_name "f"
setattribute self, "f", f
g = find_name "g"
setattribute self, "g", g
.end

.sub g
.param pmc self
.param pmc y
.return (y)
.end

.namespace [""]
.sub main @MAIN
.local pmc foo, g
init_python()

create_Foo()

#
#  foo = Foo()
#
foo = Foo()
#  g=foo.g
#
g = getattribute foo, "g"
# TODO create bound Sub inside gettattribute like so
## $I0 = isa g, "Sub"
## unless $I0 goto no_sub
## $P0 = new .BoundSub, g
## assign $P0, foo
## g = $P0
## no_sub:

#  print f(0,1)
$P0 = f(0, 1)
print_item $P0
print_newline

#  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

#  print g(3)
#$P0 = g(3)
#print_item $P0
#print_newline
.end

#

.sub init_python
.local pmc py, bs
py = newclass "Py"
.end



Re: Python PMC's

2005-08-23 Thread Sam Ruby
Chip Salzenberg wrote:
> On Tue, Aug 23, 2005 at 07:15:41PM -0400, Sam Ruby wrote:
> 
>>Leopold Toetsch wrote:
>>
>>>I've stated several times that calling conventions need changes to
>>>properly support HLLs with minor success at these times.
>>
>>With the diversity of HLLs out there, I'm not certain that it is wise to
>>declare one set of semantics "proper", thereby implicitly declaring all
>>others "improper".
> 
> Well, let's try "more coherent and less confusing", then, or maybe
> just "better".  HLLs don't have to expose the 'self' parameter if
> they don't want to.  Just extract it into a PMC register that's
> never used.

Let me try again to move the discussion from subjective adjectives to
objective code.  Consider:

  def f(x,y):
return y

  class Foo:
f = f
def g(self,y):
  return y

  foo = Foo()

  g=foo.g

  print f(0,1)
  print foo.f(2)
  print g(3)

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.

I'm open to suggestions as to what PIR code should be emitted by Pirate
to correspond to the above code.

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

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.

Precisely emulating the behavior above is an important part of
distinguishing a "Python-like" language from a true Python language, and
is necessary to pass the b0 pie-thon test (grep for __get__ to see what
I mean).

As to whether this is "more coherent and less confusing", then, or maybe
just "better"... well, lets just say that I'll leave the adjectives to
others.

- Sam Ruby


Re: Python PMC's

2005-08-23 Thread Chip Salzenberg
On Tue, Aug 23, 2005 at 07:15:41PM -0400, Sam Ruby wrote:
> Leopold Toetsch wrote:
> > I've stated several times that calling conventions need changes to
> > properly support HLLs with minor success at these times.
> 
> With the diversity of HLLs out there, I'm not certain that it is wise to
> declare one set of semantics "proper", thereby implicitly declaring all
> others "improper".

Well, let's try "more coherent and less confusing", then, or maybe
just "better".  HLLs don't have to expose the 'self' parameter if
they don't want to.  Just extract it into a PMC register that's
never used.
-- 
Chip Salzenberg <[EMAIL PROTECTED]>


Re: Python PMC's

2005-08-23 Thread Sam Ruby
Leopold Toetsch wrote:
> 
> On Aug 23, 2005, at 22:48, Sam Ruby wrote:
> 
>>> From December 16, 2004:
>>
>>   http://tinyurl.com/8smmq
> 
> Sounds like a really ugly misunderstanding, the more that I've proposed
> not to pass the object (P2 in old parlance) out of band. I've stated
> several times that calling conventions need changes to properly support
> HLLs with minor success at these times.

With the diversity of HLLs out there, I'm not certain that it is wise to
declare one set of semantics "proper", thereby implicitly declaring all
others "improper".

> What I've always said (and what is actually implemented now in the
> branch) is that methods gets the object as its first argument. A typical
> snippet in PIR code is now
> 
>   .sub __abs
>  .param pmc self
> 
> or if denoted as method:
> 
>   .sub __abs method
>  # 'self' param automagically available
> 
> The first argument of NCI or vtable methods is and was always SELF,
> which usually is the invocant and always is the object (the current only
> excpetion is an invocation through super()).

It might help to anchor this discussion if we focus on a tangible test
case.  In particular, lets look at the first few lines of the first
pie-thon test, which can be found here:

  http://svn.perl.org/parrot/trunk/languages/python/t/pie/b0.t

What code should be generated for the declaration of proto___new__ or
proto___repr__ functions?  What code should be generated for the various
assignment statements in the declaration of the method __new__ inside
the MetaToken class?  Particularly, the one involving a staticmethod?

The conclusion I came to is that there is no way to tell in advance how
a given function or method in Python is ever going to be called as there
effectively is no difference between the two.

- Sam Ruby


Re: Python PMC's

2005-08-23 Thread Leopold Toetsch


On Aug 23, 2005, at 22:48, Sam Ruby wrote:


From December 16, 2004:


  http://tinyurl.com/8smmq


Sounds like a really ugly misunderstanding, the more that I've proposed 
not to pass the object (P2 in old parlance) out of band. I've stated 
several times that calling conventions need changes to properly support 
HLLs with minor success at these times.


What I've always said (and what is actually implemented now in the 
branch) is that methods gets the object as its first argument. A 
typical snippet in PIR code is now


  .sub __abs
 .param pmc self

or if denoted as method:

  .sub __abs method
 # 'self' param automagically available

The first argument of NCI or vtable methods is and was always SELF, 
which usually is the invocant and always is the object (the current 
only excpetion is an invocation through super()).


I'm sorry if this caused confusion.


- Sam Ruby


leo



Re: Python PMC's

2005-08-23 Thread Sam Ruby
Chip Salzenberg wrote:
> I apologize to Leo for accidentally making this reply to the list.
> It was supposed to be private mail, but I hit 'y' just a _little_
> too soon.  I had no intention of embarassing anyone.  Sorry.

You did, however, cause me to cancel the email I was composing.  If
people only respond in private to emails such as the one that you
responded to, the public perception is that emails such as Leo's are
acceptable.

In any case, here is a shorter version of what I said in the email I
cancelled:

>From December 16, 2004:

  http://tinyurl.com/8smmq

The commit message for December 17, 2004:

> r7312 | rubys | 2004-12-17 22:51:48 -0500 (Fri, 17 Dec 2004) | 2 lines
> 
> Pass 'self' as the first argument on method calls

- Sam Ruby


Re: Python PMC's

2005-08-23 Thread Chip Salzenberg
I apologize to Leo for accidentally making this reply to the list.
It was supposed to be private mail, but I hit 'y' just a _little_
too soon.  I had no intention of embarassing anyone.  Sorry.

On Tue, Aug 23, 2005 at 01:04:58PM -0700, Chip Salzenberg wrote:
> On Tue, Aug 23, 2005 at 09:58:21PM +0200, Leopold Toetsch wrote:
> > Sam, please follow Parrot dev (or stop spreading FUD) - thanks.
> 
> Be gentle, please.  Parrot needs language developers.  I'm not saying
> you're right or wrong.  I'm just asking you to be a little more
> diplomatic.
> -- 
> Chip Salzenberg <[EMAIL PROTECTED]>

-- 
Chip Salzenberg <[EMAIL PROTECTED]>