class printWrapper:
def __init__(self, message):
self.message = message
def printMe(self):
print self.message
x = printWrapper("foo")
x.printMe() # prints foo
a = x.printMe
a() # bound method call; prints foo
b = printWrapper.printMe
b(x) # unbound method call; prints foo
Do we have plans on how we might implement this via Parrot?
To put it another way, the expression "foo.bar()" in Python doesn't
really parse as "invoke method bar on object foo", but rather as
"lookup attribute bar on object foo, and call the result as a
function". That's an incredibly flexible and compact semantics, and
let's you do stuff like this:
class omniWrapper:
def __init__(self, message):
self.message = message
def printMe(self):
print self.message
def __getattr__(self, attrname):
return self.printMe
z = omniWrapper("hello")
z.printMe() # prints hello
z.igloo() # also prints hello
z.anythingAtAll() # anything prints hello
That is, you can appear to be calling methods that aren't there at all.
It seems odd, but makes perfect sense in light of the above
description--method calls in Python are not what you might think, based
on how other languages act. But that would seem to imply that Python
would need a very different method call infrastructure than Perl --
a.b() in Python means something very different than $a.b() in Perl.
(That of course brings up questions of how things act when Python tries
to call a method on a Perl object--syntax, semantics.)
JEff
> Do we have plans on how we might implement this via Parrot?
Sure.
> To put it another way, the expression "foo.bar()" in Python doesn't
> really parse as "invoke method bar on object foo", but rather as
> "lookup attribute bar on object foo
Well, there isn't much difference here. "invoke method bar" implies a
method lookup that normally checks the method cache for existing
(statically built) methods. If a method isn't found there, the dynamic
plan B comes in. And if Python code overrides a method (attribute slot)
the method cache has to be invalidated.
More fun is probably to get the same inheritance ("mro") as Python.
leo
> Jeff Clites <jcl...@mac.com> wrote:
>
>> To put it another way, the expression "foo.bar()" in Python doesn't
>> really parse as "invoke method bar on object foo", but rather as
>> "lookup attribute bar on object foo
>
> Well, there isn't much difference here. "invoke method bar" implies a
> method lookup that normally checks the method cache for existing
> (statically built) methods. If a method isn't found there, the dynamic
> plan B comes in. And if Python code overrides a method (attribute slot)
> the method cache has to be invalidated.
A few things though:
1) In my case of a = x.printMe, we need to be prepared to return a
function created by currying a method using that particular instance,
and for b = printWrapper.printMe we need to return a function which
does type checking on its first argument (then calls the relevant
method on it)--certainly doable, just odd.
2) I'd expect the method cache to be per-class, but Python can change
an attribute slot on a per-instance basis (as well as a per-class
basis), so we can't really use a per-class method cache (or, we need a
flag on particular instances which tell us not to use it for them).
3) I won't mention the problem of languages which allow an object to
have instance variables and instance methods of the same name (so that
in Python, "a.b" would be ambiguous if "a" is an object from such a
language).
> More fun is probably to get the same inheritance ("mro") as Python.
Yes, true, and I guess related--Python must first look for things
overridden on the particular instance, I think, even before looking at
its class.
JEff
Random note: this sounds very much like a Df^H^HC# delegate.
> This works similarly if you do the lookup on
> the class object, but when you invoke the "function" you need to pass
> in an instance as an argument. Consider:
And this sounds very much like a Perl 5 method. In light of that, the
first part sounds like a Perl 6 curried sub.
I suspect that Python will just need slightly fancy vtables for method
and attribute lookup--nothing Parrot can't handle. It might not even
need a separate vtable for the two of them, although it should
implement both for interop.
--
Brent 'Dax' Royal-Gordon <br...@brentdax.com>
Perl and Parrot hacker
There is no cabal.
[I currently have a couple Gmail invites--contact me if you're interested.]
> 2) I'd expect the method cache to be per-class, but Python can change
> an attribute slot on a per-instance basis (as well as a per-class
> basis), so we can't really use a per-class method cache (or, we need a
> flag on particular instances which tell us not to use it for them).
The method cache is per class. But we have properties too. Per-instance
attributes end up as properties. If there is a flag or method cache
invalidation is a matter of taste and depends on method resolution
order.
> 3) I won't mention the problem of languages which allow an object to
> have instance variables and instance methods of the same name (so that
> in Python, "a.b" would be ambiguous if "a" is an object from such a
> language).
Well, Python has that very problem. By dynamically defining an instance
variable, a method with that same name becomes inaccessible.
>>> class A(object):
... def b(self):
... print "b"
...
>>> a=A()
>>> a.b()
b
>>> a.b=2
>>> a.b()
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: 'int' object is not callable
> JEff
leo
> Jeff Clites <jcl...@mac.com> wrote:
>
>> 3) I won't mention the problem of languages which allow an object to
>> have instance variables and instance methods of the same name (so that
>> in Python, "a.b" would be ambiguous if "a" is an object from such a
>> language).
>
> Well, Python has that very problem. By dynamically defining an instance
> variable, a method with that same name becomes inaccessible.
Well, for Python itself that's not a problem per se, it's a fundamental
part of the design--there's only one slot for a given name, and it can
hold a sub or something else, but it's just one slot. (You don't really
have named methods, you just have named slots that may or may not hold
subs.) That's just the way Python objects work. But for objects coming
over from another language, you might really have separate slots for
subs v. data, but if these are accessed from Python code, you don't
have a way to specify which one you mean. It's very similar to the
namespace problem with language crossing.
JEff