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

Reply via email to