Python Macros

  • Thread starter Arich Chanachai
  • Start date
R

Richard Blackwood

Andrew said:
Translating the Smalltalk notation to Python -- what are
the messages? Is it that

x.y(z)

means "send the __call__ (z)" message to the result of
the "z __getattr__ 'y'" message?

Andrew
(e-mail address removed)

In ObjC it would be send the message y with value z to object X
Say X doesn't know what to do with y
specified in X's code are instruction that tell it what object to pass
the message y to...say...U for example
So the message has been passed and basically translates into U.y(z) or
in ObjC [U y:z]
 
J

Josiah Carlson

_Most_ object-oriented languages support object orientation via the
message passing paradigm. Python included.

It's just that in Smalltalk the word "message" plays a more central
role in the (natural) language used to talk about the (programming)
language. In other (programming) languages, terms such as "method" and
"member function" tend to be used to describe the same concept.

Think of it like this:

There is object-oriented message passing (using message passing to
handle object orientation), which is what ObjC and Smalltalk use as
paradigms to describe how they work.

Then there is the asynchronous message passing, which involves queues
of messages that are polled, etc.


If your language has a stack datatype, it has a queue datatype. If it
has these, it can do asynchronous message passing.

On the other hand, no one in the Python world really describes
instance.method() as passing a message to 'instance' with the value of
'method'.

- Josiah
 
J

Jacek Generowicz

Andrew Dalke said:
Translating the Smalltalk notation to Python -- what are
the messages? Is it that

x.y(z)

means "send the __call__ (z)" message

instance(...) is syntactic sugar for instance.__call__(...) yes.
to the result of the "z __getattr__ 'y'" message?

Yes, you could look at it that way, though it is not a particularly
helpful way of looking at it.

None of this takes away from the fact that the OO paradigm supported
by Python is called the message passing paradigm.

Some might argue that this is not the message passing paradigm, as (in
their opinion) the message passing paradigm mandates that _all_
interaction with the object be done via messages, and they might
(justifiably) argue that "x.y" is _not_ really a message.

But then, many would say that Python is not object-oriented at all, as
it does not have access restriction (enforced privacy).
 
J

Jacek Generowicz

Richard Blackwood said:
Andrew said:
Translating the Smalltalk notation to Python -- what are
the messages? Is it that

x.y(z)

means "send the __call__ (z)" message to the result of
the "z __getattr__ 'y'" message?

Andrew
(e-mail address removed)

In ObjC it would be send the message y with value z to object X
Say X doesn't know what to do with y
specified in X's code are instruction that tell it what object to pass
the message y to...say...U for example

So the message has been passed and basically translates into U.y(z) or
in ObjC [U y:z]

You mean some refinement of this sort of thing:

class X(object):

a = "lives in X"

def __getattr__(self, name):
return getattr(U,name)

class U(object):

b = "lives in Y"

x = X()
print x.a
print x.b

?
 
J

Jacek Generowicz

gabriele renzi said:
Jacek Generowicz ha scritto:
_Most_ object-oriented languages support object orientation via the
message passing paradigm. Python included.

I disagree slightly.
I think the difference is really subtle, [...]

I agree completely :)
 
J

Jacek Generowicz

In my mind I have the equation "message passing = single dispatching"

I don't think that message passing implies single dispating by
necessity. After all, the visitor pattern allows you to hack in
multiple dispatch into message-passing languages. There must be other
ways too [1]
as opposed to multiple dispatching (generic functions).

But it is true that generic functions' feature of not singling out the
first argument as special, both in terms of it's syntactic position,
and the "method ownership" concept, does make multiple dispatch seem
more natural.
IOW, it seems to me that all OOP systems based on single dispatching
are more or less the same and it is just a matter of terminology
("passing a message to an object" = "calling a method of an
object").
Am I right in this simplification? Or the terms has a much more
precise meaning?

If someone can find The Canonical definition of message passing, then
I'd be interested to see it, but I fear that trying to nail down such
a definition could be a matter of considerable debate and controversy
(just as it is for "strong typing" and "object orientation" for
example).



[1] Something along these lines maybe, though I haven't got the time
to develop it beyond a crappy idea (ie I haven't tried it, I'm
sure there are mistakes, it's not very clever):

class mdm(object):
"Multiply dispatching method (message?)."

def __init__(self):
self.dispatch = {}

def add(self, method, types):
self.dispatch[types] = method

def __call__(self, *args):
return self.dispatch[self.map(type, args)](*args)

def __get__(self, ...):
# Method binding descriptor should go here
# The details escape me at the moment

class Foo(object):

bar = mdm()
def _bar(self, a,b):
# whatever
bar.add(_bar, (int, int))
def _bar(self, a,b):
# something else
bar.add(_bar, (dict, str))

del _bar


[ Orthogonal issue: Wouldn't it be great to have fully fledged
anonymous, inline functions? Then we wouldn't have to faff around with
"_bar" and "del _bar" and "bar.add", we could just write:

bar = mdm((type1, type2,
lambda self, a, b: # whatever),

(type3, type4,
lambda self, a, b: # something else))

(Or, in this case, it could be cleaned up by smuggling in an
"accumulating dictionary", to pass to the metaclass ... as discussed
in another thread last week.)

]
 
J

Jacek Generowicz

Josiah Carlson said:
On the other hand, no one in the Python world really describes
instance.method() as passing a message to 'instance' with the value of
'method'.

This is not true.

Proof by counterexample: I sometimes do.

QED.

:)
 
A

Alex Martelli

Carlos Ribeiro said:
def __getattr__(self, attrname):
# self.__dict__ contains the local dict of Dog
message = getattr(self.__dict__, attrname, None)

The only kind of *attributes* you'll find for self.__dict__ are methods
such as keys, items, copy, and so on. Attributes and items are very
different things, of course. I suspect this code is a serious bug,
i.e., the intention is *NOT* to have somedog.copy() return a copy of
somedog.__dict__ and so on. self.__dict__ will never have attrname as a
key at this point, either, or else __getattr__ would never have been
entered in the first place (don't confuse __getattr__ with the rarely
needed, rarely used __getattribute__!!!). In short, I believe this
whole part and the following if/else construct just need to be excised.

If you want to delegate attribute lookup (including method lookup) from
self to self.owner, ALL you need is:

def __getattr__(self, n): return getattr(self.owner, n)

that's it -- nothing more.


Alex
 
A

Alex Martelli

G. S. Hayes said:
def __getattr__(self, attr):
if not hasattr(self, attr):

redundant: hasattr(self, attr) will ALWAYS be false here, or else
__getattr__ wouldn't have been entered in the first place.


Alex
 
A

Alex Martelli

Jacek Generowicz said:
Some might argue that this is not the message passing paradigm, as (in
their opinion) the message passing paradigm mandates that _all_
interaction with the object be done via messages, and they might
(justifiably) argue that "x.y" is _not_ really a message.

I don't see the "justifiably" part -- how does the choice of syntax
sugar make some operation "really a message" or not?!

But then, many would say that Python is not object-oriented at all, as
it does not have access restriction (enforced privacy).

And others have put down in writing that "being really object-oriented"
absolutely requires static typing (!) -- which means that Smalltalk
isn't Object Oriented, either. The fact that people can and do say
totally idiotic things (often when they're trying to sell you snake oil,
or trying to keep their self-respect after having bought snake oil
themselves) doesn't mean much -- it's just a reflection on the natural
history of domesticated primates. _We_ of course don't need snake oil,
since we have the whole snake...


Alex
 
A

Alex Martelli

gabriele renzi said:
Jacek Generowicz ha scritto:


I disagree slightly.
I think the difference is really subtle, but there are some dict-based
languages like python and some message-based like smalltalk.
Actually I think the discriminating is having a doesNotUnderstand:-like
facility versus a __getattr__ one.

Please explain how this syntax choice "discriminates" anything
whatsoever? __getattr__ is called when some message isn't understood by
the "normal" mechanisms of the object, too.


Alex
 
A

Alex Martelli

gabriele renzi said:
ah, so the OP is asking about Higher Order Messages a-la F-Script? (or
hyper ops a-la perl6)

I don't think this can be done in pure python. You can do half of it, say:
collection >> stuff # map the stuff over the collection
or
collection >> operator << othercollection

but you cant do

stuff operator << collection

Assuming all of these identifiers are just such, you can't use the
latter syntax sugar (nor could you use the shorter 'stuff oper' sugar
either even without the << tail), but just tweak the syntax sugar
slightly (e.g. put a dot between the identifiers, which syntactically
you can't just juxtapose -- or, insert some operator there) and I'd
expect you can build whatever weird semantics you intend to (whether it
would make any _SENSE_ to go to such contortions is another issue, of
course -- not knowing what semantics you expect to associate to this not
exactly self-documenting syntax, I can't really guess).


Alex
 
J

Jacek Generowicz

I don't see the "justifiably" part -- how does the choice of syntax
sugar make some operation "really a message" or not?!

Because they might claim that attribute access being implemented via a
message is an implementation detail, and that the concept represented
by the sugar (direct attribute access) is more important in this case.

All completely pointless, of course :)

And, yes, probably not justifiable ... but who cares ?
And others have put down in writing that "being really
object-oriented" absolutely requires static typing (!)

Yes, this one really puzzles me. One of the fundamental underlying
mechanisms for implementing object orientation would have to be
run-time type identification ... which, by definition, is absent from
static type systems. So you have to smuggle some dynamic typing into
your static type system.

(I vaguely remember reading somewhere, speculations that this might
otherwise be achieved by heroic efforts in delaying fromal binding
time by some other means.)
The fact that people can and do say totally idiotic things [...]
doesn't mean much

My point exactly.
_We_ of course don't need snake oil, since we have the whole
snake...

Yes, but squeezing the oil out of the snake can be quite an effort. I
guess that's why so many people prefer the pre-extracted and packaged
product.
 
G

gabriele renzi

Alex Martelli ha scritto:
Please explain how this syntax choice "discriminates" anything
whatsoever? __getattr__ is called when some message isn't understood by
the "normal" mechanisms of the object, too.

I actually meant __getattribute__ sorry.


The point is that when you write
x.foo(y)
in py you're looking up foo, then calling it with y.
Actually you can even store x.foo away and call it later
f=x.foo

in ST you can't cause you're not doing a dict lookup when you write
x foo: y

obviously you could send another message asking for x to give you a
method foo: object


Not that one is better than other just a subtle difference.
 
G

gabriele renzi

Alex Martelli ha scritto:
Assuming all of these identifiers are just such, you can't use the
latter syntax sugar (nor could you use the shorter 'stuff oper' sugar
either even without the << tail), but just tweak the syntax sugar
slightly (e.g. put a dot between the identifiers, which syntactically
you can't just juxtapose -- or, insert some operator there) and I'd
expect you can build whatever weird semantics you intend to (whether it
would make any _SENSE_ to go to such contortions is another issue, of
course -- not knowing what semantics you expect to associate to this not
exactly self-documenting syntax, I can't really guess).

thanks for hinting the dot, I'm not going to implement this, just
thought this what was the OP was asking. I still don't understand what
he wants.

The syntax is perl6's one, and I bet you find it confusing :) but no
more than F-Script's one:
x @foo: @y

But see, OOPAL or HOM or HyperOperations are a nifty thing and yes, I
actually think they make lot of sense. I'd love to see them in python.
I think you can google for it and you'll find papers explaining it
better than I can, but basically it boils down to applying operations to
a whole collection at once, in APL style.
 
A

Alex Martelli

gabriele renzi said:
I actually meant __getattribute__ sorry.

Python lets you have either, sure. But the very existence of
__getattr__ (WAY more used and useful of __getattribute__) appears to
deny your point.

The point is that when you write
x.foo(y)
in py you're looking up foo, then calling it with y.
Actually you can even store x.foo away and call it later
f=x.foo

in ST you can't cause you're not doing a dict lookup when you write
x foo: y

obviously you could send another message asking for x to give you a
method foo: object

Exactly because of this 'obviously' part, I claim there is no deep
difference whatsoever. Currently, Python factors every fetch-and-call
operation into separate fetching and calling sub-operations, while a
typical Smalltalk implementation optimizes the common case of
fetch-and-call wrt the rarer case where you only want to fetch for now,
store the method object somewhere, and call it later. This is an
implementation detail, actually an _optimization_ detail.

Say that Python 2.5 introduced an optional __getattr_and_call__ special
method and one related bytecode. Where now a call c.z() compiles to
LOAD_FAST c
LOAD_ATTR z
CALL_FUNCTION 0
it would then compile into
LOAD_FAST c
CALL_ATTR z, 0

If c's class did define __getattr_and_call__, the latter would boil down
to type(c).__getattr_and_call__(c, 'z'); otherwise, it would instead
boil down to (like today) the equivalent of:
_temp = getattr(c, 'z')
_temp.__call__()
(for some hypothetical _temp which actually -- yet another irrelevant
implementation detail -- only lives on Python's runtime stack).

Observable differences? Essentially nil -- hopefully some potential to
be faster (otherwise it would hardly be worth the bother), but
semantically intended to have identical effects. Similarly for other
possible implementation choices for CALL_ATTR (adding a __get_and_call__
method to descriptors, to be used, if present, instead of just __get__
in such cases, for example).

A language completely unable to get a first-class "bound method" object
WOULD be substantially impoverished, sure. But as long as you can get
that kind of object, then whether you use that "getting" as the only
mechanism for calling, or introduce some "rolled-up" mechanism to
(hopefully) optimize common use cases, is a mere implementation detail
-- simplicity on one side, perhaps a tad more speed on the other.
Not that one is better than other just a subtle difference.

An _implementation_ difference, and in fact a pretty minor detail too,
not any real _language_ difference.


Alex
 
A

Alex Martelli

gabriele renzi said:
better than I can, but basically it boils down to applying operations to
a whole collection at once, in APL style.

Numeric has been doing just that for many years, and indeed using
Numeric does _feel_ to me very close to using APL in some cases, minus
the illegibility. So, I don't see any case for changing the language.


Alex
 
C

Carlos Ribeiro

The only kind of *attributes* you'll find for self.__dict__ are methods
such as keys, items, copy, and so on. Attributes and items are very
different things, of course. I suspect this code is a serious bug,
i.e., the intention is *NOT* to have somedog.copy() return a copy of
somedog.__dict__ and so on. self.__dict__ will never have attrname as a
key at this point, either, or else __getattr__ would never have been
entered in the first place (don't confuse __getattr__ with the rarely
needed, rarely used __getattribute__!!!). In short, I believe this
whole part and the following if/else construct just need to be excised.

Thanks (again!). Another dumb mistake. I have mixed up __get__attr,
descriptors, and __getattribute__ in my head, all at once, and messed
up the concepts. Too much reading and too little practice do it :).
The funny thing is that the code worked as written, at least for my
small test case, because it failed to find the dog.fetch method
anyway.
If you want to delegate attribute lookup (including method lookup) from
self to self.owner, ALL you need is:

def __getattr__(self, n): return getattr(self.owner, n)


--
Carlos Ribeiro
Consultoria em Projetos
blog: http://rascunhosrotos.blogspot.com
blog: http://pythonnotes.blogspot.com
mail: (e-mail address removed)
mail: (e-mail address removed)
 
G

gabriele renzi

Alex Martelli ha scritto:
Numeric has been doing just that for many years, and indeed using
Numeric does _feel_ to me very close to using APL in some cases, minus
the illegibility. So, I don't see any case for changing the language.

indeed the OOPAL papers considers python's Numeric, and founds the need
for still changing the language.
As I said, you can read it and found a better explanation than the one I
could give you.
 
G

gabriele renzi

Alex Martelli ha scritto:
Exactly because of this 'obviously' part, I claim there is no deep
difference whatsoever.

sorry, but no time to read all you reply, leaving in minutes.
But, it seem there is no need.
I never said there was a big difference, I said there was a subtle one
and you agree there is no deep one, no need to clutter the ml more :)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,070
Latest member
BiogenixGummies

Latest Threads

Top