Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

a Python person's experience with Ruby

11 views
Skip to first unread message

Steve Howell

unread,
Dec 8, 2007, 12:08:01 AM12/8/07
to pytho...@python.org
Python is my favorite programming language. I've used
it as my primary language for about six years now,
including four years of using it full-time in my day
job. Three months ago I decided to take a position
with a team that does a lot of things very well, but
they don't use Python. We use Ruby instead. I'd like
to share my observations about Ruby, because I think
they say important things about Python, which has been
my frame of reference.

First of all, I actually enjoy programming in Ruby.
Although I'm still fairly early on the learning curve,
I feel like I've achieved basic fluency, and it
generally stays out of the way.

(A quick disclaimer is that some of the observations I
make about Ruby may simply reflect my ignorance about
the language. I'm still learning it.)

The thing that I like least about Ruby is its
"require" mechanism. Basically, when you do "require"
in Ruby, it sort of pollutes your namespace. I much
prefer Python's explicitness.

Some surprising things that I like about Ruby:

1) It has the Perlish natural language syntax of
"raise 'foo' if condition." I never missed having
that syntax in Python, but now that I have it in Ruby,
I use it quite often.

2) On a general note, Ruby is enough like Python
that it doesn't bend my brain.

3) I actually like being able to omit parentheses in
method definitions and method calls. In Ruby you can
express "add(3,5,7)" as both "add(3,5,7)" and "add 3,
5, 7." The latter syntax is obviously more error
prone, but I don't think I've ever actually gotten bit
by it, and the code appears more clean to me.

4) Ruby forces you to explicitly make attributes for
instance variables. At first I found this clumsy, but
I've gotten used to it, and I actually kind of like it
in certain circumstances.

What I miss about Python:

1) I like the fact that Python's syntax for passing
around methods is very natural. Ruby's syntax is much
more clumsy.

2) I miss indentation. I get bitten by kEnd in Ruby
all the time.

3) I miss Python's maturity. Just to give a small
example, Python's interpreter gives more readable
syntax error messages.

Those are the things that jump out for me. I'm
curious to hear what other people have learned about
Python after maybe going away from it for a while.


____________________________________________________________________________________
Be a better friend, newshound, and
know-it-all with Yahoo! Mobile. Try it now. http://mobile.yahoo.com/;_ylt=Ahu06i62sR8HDtDypao8Wcj9tAcJ

MonkeeSage

unread,
Dec 8, 2007, 1:30:09 AM12/8/07
to

Hello,

Standard disclaimer: This response is in the spirit of sharing
knowledge and experience, as I take your post to be, not in the spirit
of advocacy of any language. All opinions I express are simply that:
my opinion.

I use both python and ruby quite often. But I came from the other
direction, starting with ruby then learning python. Overall, I think
they are both great languages, and I believe the choice in whether to
use one or the other (or both!) is determined mainly by expedience and
preference. I'll try to give my thoughts on your points, which I had
as I was learning python a few years ago, along with my current
opinions:

Ruby:

0.) I found python's concept of namespaces as defined by imported
modules (i.e., files) to be strange at first. I used "from foo import
*" a lot starting out. The main thing that I had to get my mind around
was that in ruby a namespace applies to an object (even "main", i.e.,
toplevel, is an instance of class Object), and you can "re-open"
objects to extend their namespace (or mix in "modules", which in ruby
are like a container of unbound methods that you can "include" in
another object and thereby bind those methods to that object). So
rather than "import" a module with the namespace "string," as in
python, in ruby you'd require a file that re-opens class String and
extends it. They are two different approaches (and two different ideas
of namespace pollution), but once you get your mind around both, they
are very easy to use. I almost never use "from foo import *" now in
python.

1.) I missed the infix version of conditionals that ruby provides at
first, and I would often write things like "if foo: bar" in python if
the line was short. Now it just feels more natural to write it on two
lines in python most of the time, though in ruby I still use the other
notation if the line is short.

2.) I found the same was true. I could basically translate 90% of the
ruby idioms directly into python (minor syntax issues aside), and vise
versa.

3.) I never have liked omitting parens in ruby method calls (with the
exception of methods taking no arguments, but I didn't even do that
for a long time), though many/most rubyists do use that style. One
problem with it is that it leads to ambiguities, and the parser
complains in those cases (e.g., "puts add 1, 2, 3"). However, with
predicate methods it does make it read more like a natural language
(e.g., "if Jordan.likes? :cookies"). I still parens though. ;)

4.) Yeah, it's hard when learning ruby, especially if coming from
languages that distinguish between methods and attributes, to get used
to thinking of "a.a" and "a.a=" as method calls and defining accessors
for those methods (or using one of the attr_* keywords) in the class
body. The equivalent python idiom is something like:

class A:
__a = "foo"
def __init__(self):
self.a = A.__a

Which roughly translates to this in ruby:

class A
attr_accessor :a
def initialize
@a = "foo"
end
end

Python:

1.) I also found python's style of method referencing to be a lot more
intuitive than using something like ruby's "m = method('foo');
m.call('bar')" to get a reference to foo() and call it. It's alot
cleaner to say "m = foo; m('bar')", imo. But this goes back to the
omitting parens thing, which makes it impossible to do it that way in
ruby. Though, ruby does allow some interesting things by having it
that way, e.g., letting you substitute a Proc object (e.g., a block or
lambda) for a method reference transparently.

2.) I also find layout to be a nice feature. And since I've recently
been using Haskell, it has only re-inforced that opinion. But when I
first started using python, I got bitten by IndentationError quite
often. And I kept wanting to type some closing symbol, heh. ;)

3.) I also found (and do find) python's maturity to be nice in many
ways.

Regards,
Jordan

Colin J. Williams

unread,
Dec 8, 2007, 10:23:59 AM12/8/07
to Steve Howell, pytho...@python.org
Steve Howell wrote:>
Thanks for the interesting comparison.

[snip]


> 3) I actually like being able to omit parentheses in
> method definitions and method calls. In Ruby you can
> express "add(3,5,7)" as both "add(3,5,7)" and "add 3,
> 5, 7." The latter syntax is obviously more error
> prone, but I don't think I've ever actually gotten bit
> by it, and the code appears more clean to me.
>

[snip]

I'm not sure that I like add 3, 5, 7

but it would be nice to be able to drop
the parentheses
when no argument is required.

Thus: close;
could replace close();

Colin W.

Colin J. Williams

unread,
Dec 8, 2007, 10:23:59 AM12/8/07
to pytho...@python.org, pytho...@python.org

Colin J. Williams

unread,
Dec 8, 2007, 10:29:16 AM12/8/07
to MonkeeSage, pytho...@python.org
This could be done in Python if raise
became a function,
as it has for print.

Colin W.

Colin J. Williams

unread,
Dec 8, 2007, 10:29:16 AM12/8/07
to pytho...@python.org, pytho...@python.org

Arkanes

unread,
Dec 8, 2007, 11:27:45 AM12/8/07
to pytho...@python.org

The fact that you can do this in Ruby and not in Python is why passing
callables in Ruby is awkward and it's extremely natural in Python. In
Ruby, of course, you don't pass callables around as much, using blocks
instead, so it works out there. But it's an example of some of the
fundamental syntax differences between the languages.

Bruno Desthuilliers

unread,
Dec 8, 2007, 1:42:59 PM12/8/07
to
MonkeeSage a écrit :

> On Dec 7, 11:08 pm, Steve Howell <showel...@yahoo.com> wrote:
>
(snip)

>> 4) Ruby forces you to explicitly make attributes for
>> instance variables. At first I found this clumsy, but
>> I've gotten used to it, and I actually kind of like it
>> in certain circumstances.

> 4.) Yeah, it's hard when learning ruby, especially if coming from


> languages that distinguish between methods and attributes,

which is not the case in Python

> to get used
> to thinking of "a.a" and "a.a=" as method calls and defining accessors
> for those methods (or using one of the attr_* keywords) in the class
> body.

Python has an equivalent support for computed attributes, using property
or a custom descriptors. While it's a bit lower-level than Ruby, it's
still quite easy to use and IMHO a bit more powerful.

> The equivalent python idiom is something like:
>
> class A:
> __a = "foo"
> def __init__(self):
> self.a = A.__a

WTF ???

> Which roughly translates to this in ruby:
>
> class A
> attr_accessor :a
> def initialize
> @a = "foo"
> end
> end

The Python translation of the above Ruby snippet is actually way more
simple:

class A(object):
def __init__(self):
self.a = "foo"


> Python:
>
> 1.) I also found python's style of method referencing to be a lot more
> intuitive than using something like ruby's "m = method('foo');
> m.call('bar')" to get a reference to foo() and call it. It's alot
> cleaner to say "m = foo; m('bar')", imo. But this goes back to the
> omitting parens thing, which makes it impossible to do it that way in
> ruby.

Yeps. This is where the real and fundamental difference between Ruby and
Python becomes evident. Both have support for transparent computed
attributes, but the way it's implemented is totally different - in Ruby,
by not having a call operator at all (I mean, the parens), in Python by
having both an explicit call operator and an explicit protocol for
computed attributes (the descriptor protocol). Not to say one is better
than the other, but that while both languages have similar features
(and, at first look, similar syntaxes), they really have totally
different object models.

> Though, ruby does allow some interesting things by having it
> that way, e.g., letting you substitute a Proc object (e.g., a block or
> lambda) for a method reference transparently.

Care to give an example ? I don't have enough working experience with
Ruby to be sure I understand what you mean here.

> 2.) I also find layout to be a nice feature. And since I've recently
> been using Haskell, it has only re-inforced that opinion. But when I
> first started using python, I got bitten by IndentationError quite
> often. And I kept wanting to type some closing symbol, heh. ;)

The nice thing with Python is that it lets you use the closing symbol
you want, as long as you prefix it with a '#' !-)

Bruno Desthuilliers

unread,
Dec 8, 2007, 1:44:18 PM12/8/07
to
Colin J. Williams a écrit :

This just could not work given Python's object model. The parens
actually *are* the call operator.

MonkeeSage

unread,
Dec 8, 2007, 2:23:57 PM12/8/07
to
On Dec 8, 12:42 pm, Bruno Desthuilliers

<bdesth.quelquech...@free.quelquepart.fr> wrote:
> MonkeeSage a écrit :
>
> > On Dec 7, 11:08 pm, Steve Howell <showel...@yahoo.com> wrote:
>
> (snip)
> >> 4) Ruby forces you to explicitly make attributes for
> >> instance variables. At first I found this clumsy, but
> >> I've gotten used to it, and I actually kind of like it
> >> in certain circumstances.
> > 4.) Yeah, it's hard when learning ruby, especially if coming from
> > languages that distinguish between methods and attributes,
>
> which is not the case in Python

It is, I just wasn't absolutely precise (uh-oh, here comes the
semantics police! -- don't pass GO, don't collect $200, go strait to
jail!). Python *does* distinguish between instance/class vars and
instance/class methods. But in ruby no such distinction exists.
Accessing a "variable" in ruby == calling object.var. I.e., in ruby,
when you say "blah.x" that translates to "blah.send(:x)", whether :x
is a "variable" or a "method," since *everything* is a method. The
call model of ruby is more like smalltalk.

Not really. In ruby an ivar is accessible within the class *only*, but
not from without (like a mangled python class var), unless you declare
an accessor (or write the accessor methods yourself). So my example is
closer, and is not a WTF, if you know how ruby works.

> > 1.) I also found python's style of method referencing to be a lot more
> > intuitive than using something like ruby's "m = method('foo');
> > m.call('bar')" to get a reference to foo() and call it. It's alot
> > cleaner to say "m = foo; m('bar')", imo. But this goes back to the
> > omitting parens thing, which makes it impossible to do it that way in
> > ruby.
>
> Yeps. This is where the real and fundamental difference between Ruby and
> Python becomes evident. Both have support for transparent computed
> attributes, but the way it's implemented is totally different - in Ruby,
> by not having a call operator at all (I mean, the parens), in Python by
> having both an explicit call operator and an explicit protocol for
> computed attributes (the descriptor protocol). Not to say one is better
> than the other, but that while both languages have similar features
> (and, at first look, similar syntaxes), they really have totally
> different object models.

Yes and no. I'll leave it at that. If you want to know more, do your
homework. :P

> > Though, ruby does allow some interesting things by having it
> > that way, e.g., letting you substitute a Proc object (e.g., a block or
> > lambda) for a method reference transparently.
>
> Care to give an example ? I don't have enough working experience with
> Ruby to be sure I understand what you mean here.

For example, any place expecting a foo (method reference), can be
exchanged with a { "bar" } block or a lambda { "baz" }.

> > 2.) I also find layout to be a nice feature. And since I've recently
> > been using Haskell, it has only re-inforced that opinion. But when I
> > first started using python, I got bitten by IndentationError quite
> > often. And I kept wanting to type some closing symbol, heh. ;)
>
> The nice thing with Python is that it lets you use the closing symbol
> you want, as long as you prefix it with a '#' !-)

LOL. Well, yes, I used to do that, but I got over that irrational
urge. ;)

Regards,
Jordan

Steve Howell

unread,
Dec 8, 2007, 2:56:51 PM12/8/07
to Bruno Desthuilliers, pytho...@python.org
--- Bruno Desthuilliers
<bdesth.qu...@free.quelquepart.fr> wrote:

> Colin J. Williams a écrit :

> > I'm not sure that I like add 3, 5, 7
> >
> > but it would be nice to be able to drop the
> parentheses
> > when no argument is required.
> >
> > Thus: close;
> > could replace close();
>
> This just could not work given Python's object
> model. The parens
> actually *are* the call operator.
>

I mostly agree with you, but in the specific use case
of having just a single token on a line, you could
argue that Python could DWIM on calling an object if
the object is callable, since otherwise it's just a
no-op. I think the argument against doing that is
more based on explicit-vs.-implicit principle versus
actual constraints of the object model.

Another aspect of Ruby is that the final expression
evaluated in a method actually gets returned as the
result of a method, which has further implications on
whether "close" is simply evaluated or called.


____________________________________________________________________________________
Never miss a thing. Make Yahoo your home page.
http://www.yahoo.com/r/hs

I V

unread,
Dec 8, 2007, 4:14:03 PM12/8/07
to
On Sat, 08 Dec 2007 11:23:57 -0800, MonkeeSage wrote:
>> > The equivalent python idiom is something like:
>>
>> > class A:
>> > __a = "foo"
>> > def __init__(self):
>> > self.a = A.__a
[...]

>> > Which roughly translates to this in ruby:
>>
>> > class A
>> > attr_accessor :a
>> > def initialize
>> > @a = "foo"
>> > end
>> > end
[...]

> Not really. In ruby an ivar is accessible within the class *only*, but
> not from without (like a mangled python class var), unless you declare
> an accessor (or write the accessor methods yourself). So my example is
> closer, and is not a WTF, if you know how ruby works.

In your python example, the class attribute is mangled, but the instance
attribute isn't, whereas your ruby code has no class attribute, and an
instance attribute that isn't (directly) accessible outside the class.
The equivalent in python would involve a mangled instance attribute,
like:

class A(object):
def __init__(self):
self.__a = "foo"
def get_a(self):
return self.__a
def set_a(self, val):
self.__a = val
a = property(get_a, set_a)

Bruno Desthuilliers

unread,
Dec 8, 2007, 5:54:39 PM12/8/07
to
MonkeeSage a écrit :
> On Dec 8, 12:42 pm, Bruno Desthuilliers
> <bdesth.quelquech...@free.quelquepart.fr> wrote:
>
>>MonkeeSage a écrit :
>>
>>
>>>On Dec 7, 11:08 pm, Steve Howell <showel...@yahoo.com> wrote:
>>
>>(snip)
>>
>>>> 4) Ruby forces you to explicitly make attributes for
>>>>instance variables. At first I found this clumsy, but
>>>>I've gotten used to it, and I actually kind of like it
>>>>in certain circumstances.
>>>
>>>4.) Yeah, it's hard when learning ruby, especially if coming from
>>>languages that distinguish between methods and attributes,
>>
>>which is not the case in Python
>
>
> It is, I just wasn't absolutely precise (uh-oh, here comes the
> semantics police! -- don't pass GO, don't collect $200, go strait to
> jail!). Python *does* distinguish between instance/class vars and
> instance/class methods. But in ruby no such distinction exists.
> Accessing a "variable" in ruby == calling object.var. I.e., in ruby,
> when you say "blah.x" that translates to "blah.send(:x)", whether :x
> is a "variable" or a "method," since *everything* is a method. The
> call model of ruby is more like smalltalk.

I'm sorry to have to insist: Python doesn't distinguish between methods
and attributes. Calling a method in Python is really 1/ looking up an
attribute then 2/ applying the call operator on what the lookup eval'd
to. As a matter of fact, you can stop at the first step, and you'll have
a reference to whatever the lookup mechanism yielded for the given
attribute name on the given object. FWIW, Python's functions are plain
objects, and when used as attributes are stored in the same place as any
other attribute.

> Not really.

Yes, really. Sorry to have to insist, but...

> In ruby an ivar is accessible within the class *only*, but
> not from without (like a mangled python class var), unless you declare
> an accessor (or write the accessor methods yourself).

Your Ruby snippets uses attr_accessor, which gives direct, uncontrolled
read/write access to the attribute. So I maintain that the *exact*
semantic equivalent in Python of your Ruby snippet is a plain attribute.

> So my example is
> closer, and is not a WTF, if you know how ruby works.

I know enough about Ruby to understand this snippet, and enough about
Python to tell your Python example is a WTF.

FWIW, your Python snippet ends up doing the same thing as mine - that
is, it defines a plain instance attribute named 'a' - but uses a
reference to class attribute instead of a string literal as the initial
value of the instance attribute. Since Python strings are immutable, the
final result is the same wrt/ the instance attribute - it's just overly
complicated, hence the WTF label.

OTHO, your Python code also defines a class attribute which doesn't
exist in the Ruby snippet. Mine doesn't imply any class attribute. So my
Python translation is way closer to the Ruby original !-)

If you what you had in mind was an example of a computed attribute,
here's the correct code:

class A(object):
@apply
def a():
def fget(self):
return self._a
def fset(self, val):
self._a = val
return property(**locals())


def __init__(self):
self.a = "foo"

Now since we're just getting/setting the attribute, all these
indirection levels are totally useless, so in such a case we just use a
plain attribute. So my first exemple (plain attribute) is effectively
the *exact* semantic equivalent of your Ruby snippet. CQFD.


>>>1.) I also found python's style of method referencing to be a lot more
>>>intuitive than using something like ruby's "m = method('foo');
>>>m.call('bar')" to get a reference to foo() and call it. It's alot
>>>cleaner to say "m = foo; m('bar')", imo. But this goes back to the
>>>omitting parens thing, which makes it impossible to do it that way in
>>>ruby.
>>
>>Yeps. This is where the real and fundamental difference between Ruby and
>>Python becomes evident. Both have support for transparent computed
>>attributes, but the way it's implemented is totally different - in Ruby,
>>by not having a call operator at all (I mean, the parens), in Python by
>>having both an explicit call operator and an explicit protocol for
>>computed attributes (the descriptor protocol). Not to say one is better
>>than the other, but that while both languages have similar features
>>(and, at first look, similar syntaxes), they really have totally
>>different object models.
>
> Yes and no. I'll leave it at that. If you want to know more, do your
> homework. :P

Hmmm... Sorry, but from this thread and another one here about the
distinction between attributes and method, I have the strong impression
you have more homework to do than me - at least wrt/ Python's object
model. May I suggest you take a look at the doc about the lookup
mechanism, the descriptor protocol and the call operator ?-)

>>>Though, ruby does allow some interesting things by having it
>>>that way, e.g., letting you substitute a Proc object (e.g., a block or
>>>lambda) for a method reference transparently.
>>
>>Care to give an example ? I don't have enough working experience with
>>Ruby to be sure I understand what you mean here.
>
>
> For example, any place expecting a foo (method reference), can be
> exchanged with a { "bar" } block or a lambda { "baz" }.

You mean that a method reference, a block and a lambda can all be called
? Yes, fine. Now I don't really see how it's very different from Python
(except of course for the fact that Python doesn't have blocks).

Sorry to be dump, but a more concrete exemple might help here. I mean, a
code snippet.

Regards,

Bruno Desthuilliers

unread,
Dec 8, 2007, 6:11:23 PM12/8/07
to
Steve Howell a écrit :

> --- Bruno Desthuilliers
> <bdesth.qu...@free.quelquepart.fr> wrote:
>
>
>>Colin J. Williams a écrit :
>>
>>>I'm not sure that I like add 3, 5, 7
>>>
>>>but it would be nice to be able to drop the
>>
>>parentheses
>>
>>>when no argument is required.
>>>
>>>Thus: close;
>>>could replace close();
>>
>>This just could not work given Python's object
>>model. The parens
>>actually *are* the call operator.
>>
>
>
> I mostly agree with you, but in the specific use case
> of having just a single token on a line, you could
> argue that Python could DWIM on calling an object if
> the object is callable, since otherwise it's just a
> no-op.

It's not. If the name is not defined, it raises an exception (either a
NameError or an AttributeError). And if the name resolves to a computed
attribute, the getter for this computed attribute will be invoked - with
possible side effects.

> I think the argument against doing that is
> more based on explicit-vs.-implicit principle versus
> actual constraints of the object model.

I'd say that the object model being the work of a strong proponent of
the explicit-vs.-implicit principle, it's probably another
chicken-and-egg problem - so we are both right here !-)

> Another aspect of Ruby is that the final expression
> evaluated in a method actually gets returned as the
> result of a method,

Unless there's an explict return before...

> which has further implications on
> whether "close" is simply evaluated or called.

I'm sorry but I'm not sure I get the point here.

Richard Jones

unread,
Dec 8, 2007, 6:35:02 PM12/8/07
to
Bruno Desthuilliers wrote:
> class A(object):
> @apply
> def a():
> def fget(self):
> return self._a
> def fset(self, val):
> self._a = val
> return property(**locals())
> def __init__(self):
> self.a = "foo"

That property setup seems overly complicated. As far as I can see, it only
avoids defining the setter in the class namespace, yet is more complicated
and obfuscated to boot ;)

class A(object):
def set_a(self, value):
self._a = value
a = property(lambda self: self._a, set_a)

Note that this differs from a regular attribute because "a" is not deletable
from instances (the property defines no deleter).


Richard

Steve Howell

unread,
Dec 8, 2007, 6:59:12 PM12/8/07
to Bruno Desthuilliers, pytho...@python.org

--- Bruno Desthuilliers >
> > Another aspect of Ruby is that the final
> expression
> > evaluated in a method actually gets returned as
> the
> > result of a method,
>
> Unless there's an explict return before...
>
> > which has further implications on
> > whether "close" is simply evaluated or called.
>
> I'm sorry but I'm not sure I get the point here.

I'm just giving another example that the following
seemingly innocuous line of code has lots of side
effects in both languages, but the two languages
differ:

transaction.finish # last line in method

1) Some one new to Python might be surprised that
finish never gets invoked.

2) Some new to Ruby might be surprised that the
command above might actually cause the enclosing
method to return a non-nil value.

For this code:

return table.get_apples # last line of get_getter()

1) Some one new to Python might be surprised to see
this code when get_apples is not explicitly written in
MyTable.

2) Some one new to Ruby might be surprised that
get_getter()() does not work as expected.

Bruno Desthuilliers

unread,
Dec 8, 2007, 7:15:39 PM12/8/07
to
Richard Jones a écrit :

> Bruno Desthuilliers wrote:
>
>>class A(object):
>> @apply
>> def a():
>> def fget(self):
>> return self._a
>> def fset(self, val):
>> self._a = val
>> return property(**locals())
>> def __init__(self):
>> self.a = "foo"
>
>
> That property setup seems overly complicated. As far as I can see, it only
> avoids defining the setter in the class namespace,

Yes. That's mosly the point.

> yet is more complicated
> and obfuscated to boot ;)

Well, that's your POV, so what can I say ? It's indeed a bit hackish,
and requires a couple minutes of attention the first time you see it.
And you just have to learn it once !-)

Now I'd certainly prefer something like:

class A(object):
@propget
def a(self):
return self._a
@propset
def a(self, val):
self._a = val

But until there's something similar *builtin*, I'll stick to the @apply
trick.

Steve Howell

unread,
Dec 8, 2007, 7:19:50 PM12/8/07
to pytho...@python.org

--- Richard Jones <richar...@optushome.com.au>
wrote:

>
> class A(object):
> def set_a(self, value):
> self._a = value
> a = property(lambda self: self._a, set_a)
>
> Note that this differs from a regular attribute
> because "a" is not deletable
> from instances (the property defines no deleter).
>

The use case I was actually considering actually
doesn't require much magic in either language.

I commonly want to write code like this:

e = Employee('jim', 'accounting', 50)
print e.name
print e.department
print e.salary
e.update_salary(percent=.10)
e.update_salary(percent=.5)

I want the name, department, and salary always exposed
to me. But suppose in Employee's innards, it keeps a
cache of the number of raises Jim has been given, and
this cache is very implementation-sensitive.

The way I achieve this is different in each language:

1) In Python I get name, department, and salary
exposed for free, but I need to make a more conscious
decision to hide e.compensation_tracker, which I do by
renaming it to e.__compensation_tracker.

2) In Ruby I get compensation_tracker fully
hidden/encapsulated for free, but I have to make a
more conscious decision to expose name, department,
and salary, which I get by saying:

attr_reader :name, :department, :salary

Obviously, things can get a lot more complicated than
this scenario, and I think both languages are pretty
flexible, but flexible in a different way.

Kay Schluehr

unread,
Dec 9, 2007, 2:25:43 AM12/9/07
to
On Dec 8, 8:56 pm, Steve Howell <showel...@yahoo.com> wrote:
> --- Bruno Desthuilliers

>
> <bdesth.quelquech...@free.quelquepart.fr> wrote:
> > Colin J. Williams a écrit :
> > > I'm not sure that I like add 3, 5, 7
>
> > > but it would be nice to be able to drop the
> > parentheses
> > > when no argument is required.
>
> > > Thus: close;
> > > could replace close();
>
> > This just could not work given Python's object
> > model. The parens
> > actually *are* the call operator.
>
> I mostly agree with you, but in the specific use case
> of having just a single token on a line, you could
> argue that Python could DWIM on calling an object if
> the object is callable, since otherwise it's just a
> no-op.

Argh! I smell context sensitive semantics which is the road to
language design hell. Fortunately this hell is already occupied by
Perl and Larry Wall is a charming and funky guy. You know what look
for.

Arnaud Delobelle

unread,
Dec 9, 2007, 6:11:04 AM12/9/07
to
On Dec 9, 12:15 am, Bruno Desthuilliers

<bdesth.quelquech...@free.quelquepart.fr> wrote:
> Richard Jones a écrit :
>
>
>
> > Bruno Desthuilliers wrote:
>
> >>class A(object):
> >> @apply
> >> def a():
> >> def fget(self):
> >> return self._a
> >> def fset(self, val):
> >> self._a = val
> >> return property(**locals())
> >> def __init__(self):
> >> self.a = "foo"
>
> > That property setup seems overly complicated. As far as I can see, it only
> > avoids defining the setter in the class namespace,
>
> Yes. That's mosly the point.
>
> > yet is more complicated
> > and obfuscated to boot ;)
>
> Well, that's your POV, so what can I say ? It's indeed a bit hackish,
> and requires a couple minutes of attention the first time you see it.
> And you just have to learn it once !-)

Perhaps 'return property(fget, fset)' would be easier to make sense of
than **locals()

> Now I'd certainly prefer something like:
>
> class A(object):
> @propget
> def a(self):
> return self._a
> @propset
> def a(self, val):
> self._a = val
>
> But until there's something similar *builtin*, I'll stick to the @apply
> trick.

At first sight, I like the look of this. Obviously I can't provide a
builtin implementation, but there's an easy way to achieve this. It
uses sys._getframe but there is no need to fiddle with metaclasses:

from sys import _getframe

def _makeprop(frame, name, **d):
p = frame.f_locals.get(name, None)
args = {}
if isinstance(p, property):
args = dict(fget=p.fget, fset=p.fset, fdel=p.fdel,
doc=p.__doc__)
args.update(d)
return property(**args)

def propget(f):
return _makeprop(_getframe(1), f.__name__, fget=f)

def propset(f):
return _makeprop(_getframe(1), f.__name__, fset=f)

def propdel(f):
return _makeprop(_getframe(1), f.__name__, fdel=f)

if __name__ == '__main__':
class Foo(object):
a = property(doc="mod10 attribute")


@propget
def a(self):
return self._a
@propset

def a(self, a):
self._a = a % 10
@propdel
def a(self):
del self._a

f = Foo()
f.a = 42
assert f.a == 42 % 10

Lou Pecora

unread,
Dec 9, 2007, 12:55:32 PM12/9/07
to
In article <475ae612$0$645$426a...@news.free.fr>,
Bruno Desthuilliers <bdesth.qu...@free.quelquepart.fr> wrote:

> > Thus: close;
> > could replace close();

Wouldn't this give an ambiguity?

afcn=close # make an "alias" to the close function
val=close() # set val to the return value of the close function

--
-- Lou Pecora

Steve Howell

unread,
Dec 9, 2007, 1:40:38 PM12/9/07
to pytho...@python.org
After starting this discussion thread, I found the
link below:

http://www.b-list.org/weblog/2006/jun/18/lets-talk-about-python-and-ruby/

If you're like me--struggling to learn Ruby while
having Python as your primary point of reference--you
might find some of the points informative. I suspect
vice versa as well.

Bruno Desthuilliers

unread,
Dec 9, 2007, 1:45:52 PM12/9/07
to
Lou Pecora a écrit :

> In article <475ae612$0$645$426a...@news.free.fr>,
> Bruno Desthuilliers <bdesth.qu...@free.quelquepart.fr> wrote:
>
>
>>>Thus: close;
>>>could replace close();

*Please* give proper attribution. I'd *never* suggest such a thing.

>
> Wouldn't this give an ambiguity?
>
> afcn=close # make an "alias" to the close function
> val=close() # set val to the return value of the close function
>

The point of Colin (who was the one making this suggestion) was that
parens could be omitted if there was no LHS.

MonkeeSage

unread,
Dec 9, 2007, 2:58:05 PM12/9/07
to
On Dec 8, 4:54 pm, Bruno Desthuilliers

Except that pthon does differentiate, as python variables are not
callable, whereas everything in ruby is callable. blah.a in ruby means
blah.send(:a). Which is why you need an accessor to get at instance
variables, since as variables they exist in the scope scope of the
class, but they are not callable so they are not attributes of the
instance.

No, it's not at all.

class A
attr_accessor :a # == self.a,
# accessible to instances of A
def initialize
@a = "foo" # A.__a
# only accessible from class scope of A
end
end

Once again, there is no such thing as an attribute that is not a
method in ruby, and there is no such thing as setting an *attribute*
("=" is a method also). You're trying to *re-implement* rubys
mechanism in python in your example, but in pythons mechanism, all
attributes already have built-in getter/setter. So the correct analogy
is a variable that is accessible from within the classes scope only
(A.__a), and then exposed to instances through an attribute (self.a).
Your example leaves out a variable accessible only from within the
scope of the class, and adds a new attribute accessible from the
instance (_a).

> >>>1.) I also found python's style of method referencing to be a lot more
> >>>intuitive than using something like ruby's "m = method('foo');
> >>>m.call('bar')" to get a reference to foo() and call it. It's alot
> >>>cleaner to say "m = foo; m('bar')", imo. But this goes back to the
> >>>omitting parens thing, which makes it impossible to do it that way in
> >>>ruby.
>
> >>Yeps. This is where the real and fundamental difference between Ruby and
> >>Python becomes evident. Both have support for transparent computed
> >>attributes, but the way it's implemented is totally different - in Ruby,
> >>by not having a call operator at all (I mean, the parens), in Python by
> >>having both an explicit call operator and an explicit protocol for
> >>computed attributes (the descriptor protocol). Not to say one is better
> >>than the other, but that while both languages have similar features
> >>(and, at first look, similar syntaxes), they really have totally
> >>different object models.
>
> > Yes and no. I'll leave it at that. If you want to know more, do your
> > homework. :P
>
> Hmmm... Sorry, but from this thread and another one here about the
> distinction between attributes and method, I have the strong impression
> you have more homework to do than me - at least wrt/ Python's object
> model. May I suggest you take a look at the doc about the lookup
> mechanism, the descriptor protocol and the call operator ?-)

Sure. But as I understand, every attribute in python is a value, and
some values are "tagged" as callable. And this makes a distinction
between attributes that are callable (methods) and attributes that are
not. In ruby there is no such thing as a non-callable attribute. My
comment was wrt saying that they both have "support for transparent
computed attributes," since there is no computation of what kind of
attribute it is on the ruby model. Every attribute access is directly
translatable into object.send(symbol).

> >>>Though, ruby does allow some interesting things by having it
> >>>that way, e.g., letting you substitute a Proc object (e.g., a block or
> >>>lambda) for a method reference transparently.
>
> >>Care to give an example ? I don't have enough working experience with
> >>Ruby to be sure I understand what you mean here.
>
> > For example, any place expecting a foo (method reference), can be
> > exchanged with a { "bar" } block or a lambda { "baz" }.
>
> You mean that a method reference, a block and a lambda can all be called
> ? Yes, fine. Now I don't really see how it's very different from Python
> (except of course for the fact that Python doesn't have blocks).
>
> Sorry to be dump, but a more concrete exemple might help here. I mean, a
> code snippet.
>
> Regards,

Not just callable, but interchangeable. My point was that in ruby, if
you use a block or a lambda as a HOF, you have to use #call / #[] /
yield keyword on it to call it.

def foo(a)
puts a
end
bar = lambda { | a | puts a }

# these do the same thing
[1,2,3].each(&bar)
[1,2,3].each(&method(:foo))

That's not to say it's better than python (like I said, I personally I
like pythons referencing / calling convention a little better), it's
just that since Proc objects already have that call syntax in ruby,
making method references use it also allows them to be interchanged (w/
o having to do method(:foo).to_proc).

Regards,
Jordan

MonkeeSage

unread,
Dec 9, 2007, 3:02:40 PM12/9/07
to
On Dec 9, 1:58 pm, MonkeeSage <MonkeeS...@gmail.com> wrote:

> Sure. But as I understand, every attribute in python is a value,

sorry...*references* a value

Steve Howell

unread,
Dec 9, 2007, 3:38:37 PM12/9/07
to pytho...@python.org

--- MonkeeSage <Monke...@gmail.com> wrote:
>
> Not just callable, but interchangeable. My point was
> that in ruby, if
> you use a block or a lambda as a HOF, you have to
> use #call / #[] /
> yield keyword on it to call it.
>
> def foo(a)
> puts a
> end
> bar = lambda { | a | puts a }
>
> # these do the same thing
> [1,2,3].each(&bar)
> [1,2,3].each(&method(:foo))
>
> That's not to say it's better than python (like I
> said, I personally I
> like pythons referencing / calling convention a
> little better), it's
> just that since Proc objects already have that call
> syntax in ruby,
> making method references use it also allows them to
> be interchanged (w/
> o having to do method(:foo).to_proc).
>

Jordan and others, thanks for all your posts; I am
learning a lot about both languages.

This is what I've gathered so far.

Python philosophy:
passing around references to methods should be
natural (i.e. my_binary_op = math.add)
calling methods should be explicit (use parens)
the use of setters/getters varies among Python
programmers; properties, decorators, special methods,
etc. can be used judiciously to affect the interface

Ruby philosophy:
a method itself should be callable without parens
you can get a reference to a chunk of code, but
then you need a little extra syntax, beyond just a
variable name and parens, to eventually call it
(yield, &, call, etc.)
when referring to methods, you can use :symbols to
name the method you're interested in without actually
calling it

My personal experience:

Even after doing lots of Python, I occasionally got
bitten by the pitfall of omitting the parens when I
meant to call something, but it was never major pain.
(I never made the opposite mistake, in case you're
wondering.)

Despite the pitfall above, I always liked the
tradeoff that Python gave me more natural syntax for
passing around methods. (And, more fundamentally, I
like the Python notion of binding "general" things to
a name.)

As somebody just starting to use Ruby, I actually
like omitting parens in method calls, which I view as
the more common case. I admit some cost here, though,
in simple churn of the code due to the fact that some
people like having parens for aesthetic reasons.

I was surprised in Ruby by how seldom I really pass
references to methods around, but it is definitely
something I want to understand better.

I hope this adds a little perspective, and please feel
free to correct me in cases where I'm either imprecise
or just flat out wrong.

I V

unread,
Dec 9, 2007, 4:10:21 PM12/9/07
to
On Sun, 09 Dec 2007 11:58:05 -0800, MonkeeSage wrote:
> class A
> attr_accessor :a # == self.a,
> # accessible to instances of A
> def initialize
> @a = "foo" # A.__a
> # only accessible from class scope of A
> end
> end
>
> Once again, there is no such thing as an attribute that is not a method
> in ruby, and there is no such thing as setting an *attribute* ("=" is a
> method also). You're trying to *re-implement* rubys mechanism in python
> in your example, but in pythons mechanism, all attributes already have
> built-in getter/setter. So the correct analogy is a variable that is
> accessible from within the classes scope only (A.__a), and then exposed
> to instances through an attribute (self.a). Your example leaves out a
> variable accessible only from within the scope of the class, and adds a
> new attribute accessible from the instance (_a).

Either I'm not understanding you, or you're not understanding what A.__a
means in python. A.__a is a class attribute, not an instance attribute -
it's equivalent to @@a in ruby, not @a. If I understand what you're
saying, a better python example to make your point might be:

class A(object):
def __init__(self):
self.__a = "foo" # equivalent to @a
self.a = self.__a # exposes self.__a

Except that this only allows you to access '__a' via the exposed
attribute 'a', not bind it to a new object. If you do:

inst = A()
inst.a = "bar"

you don't modify inst.__a, unlike the following ruby code, which does
modify @a .

inst = A.new
inst.a = "bar"

MonkeeSage

unread,
Dec 9, 2007, 4:24:31 PM12/9/07
to
On Dec 9, 3:10 pm, I V <ivle...@gmail.com> wrote:
> On Sun, 09 Dec 2007 11:58:05 -0800, MonkeeSage wrote:
> > class A
> > attr_accessor :a # == self.a,
> > # accessible to instances of A
> > def initialize
> > @a = "foo" # A.__a
> > # only accessible from class scope of A
> > end
> > end
>
> > Once again, there is no such thing as an attribute that is not a method
> > in ruby, and there is no such thing as setting an *attribute* ("=" is a
> > method also). You're trying to *re-implement* rubys mechanism in python
> > in your example, but in pythons mechanism, all attributes already have
> > built-in getter/setter. So the correct analogy is a variable that is
> > accessible from within the classes scope only (A.__a), and then exposed
> > to instances through an attribute (self.a). Your example leaves out a
> > variable accessible only from within the scope of the class, and adds a
> > new attribute accessible from the instance (_a).
>
> Either I'm not understanding you, or you're not understanding what A.__a
> means in python. A.__a is a class attribute, not an instance attribute -
> it's equivalent to @@a in ruby, not @a.

I said previously that A.__a is a class variable. Since I was only
using it to show that @a is not exposed as an attribute, I just used
A.__a, but you're right, it would have been better to use self.__a.

> If I understand what you're
> saying, a better python example to make your point might be:
>
> class A(object):
> def __init__(self):
> self.__a = "foo" # equivalent to @a
> self.a = self.__a # exposes self.__a

Thanks.

> Except that this only allows you to access '__a' via the exposed
> attribute 'a', not bind it to a new object. If you do:
>
> inst = A()
> inst.a = "bar"
>
> you don't modify inst.__a, unlike the following ruby code, which does
> modify @a .
>
> inst = A.new
> inst.a = "bar"

I understand. That's why I said it was a rough translation of the ruby
code. I was only trying to say that it's strange when learning ruby,
to get your head around the idea that instance (and class) variables
are not attributes; that all attributes are callable. The example was
merely to demonstrate the distinction between instance method and
instance variable in ruby. The python isn't supposed to have the exact
same behavior, just a similar semantic.

Regards,
Jordan

Bruno Desthuilliers

unread,
Dec 9, 2007, 4:51:12 PM12/9/07
to

I beg your pardon ?

Python 2.4.3 (#1, Mar 12 2007, 23:32:01)
[GCC 3.3.4 20040623 (Gentoo Linux 3.3.4-r1, ssp-3.3.2-2, pie-8.7.6)] on
linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> class Toto(object):
... def test(self): print self
... def __call__(self): print self
...
>>> def boo(): print "boo"
...
>>> Toto
<class '__main__.Toto'>
>>> # Toto is a variable. Is it callable ?
...
>>> callable(Toto)
True
>>> Toto()
<__main__.Toto object at 0x4033492c>
>>> t = Toto()
>>> t
<__main__.Toto object at 0x403344cc>
>>> # t is a variable. Is it callable ?
... callable(t)
True
>>> t()
<__main__.Toto object at 0x403344cc>
>>> t.test
<bound method Toto.test of <__main__.Toto object at 0x403344cc>>
>>> # t.test is a variable. is it callable ?
... callable(t.test)
True
>>> t.test()
<__main__.Toto object at 0x403344cc>
>>> t.foo
Traceback (most recent call last):
File "<stdin>", line 1, in ?
AttributeError: 'Toto' object has no attribute 'foo'
>>> t.foo = boo
>>> t.foo
<function boo at 0x4032f304>
>>> # t.foo is a variable. Is it callable ?
... callable(t.foo)
True
>>> t.foo()
boo
>>>

> whereas everything in ruby is callable. blah.a in ruby means
> blah.send(:a).

Ok, I see where the problem is. We definitively don't have the same
definition of 'callable'. In Python, a callable is an object that can be
called - that is, you can apply the call operator to it. You'd better
get use to this definition when talking about Python, FWIW !-)

What you say is that in Ruby, you're *always* going thru a method call
when accessing an attribute (from outside at least). The fact is that
Ruby is built on 'true' (ie: à la Smalltalk) message passing, when
Python is built on the attribute lookup operator and the call operator.
As I said, while Python and Ruby have similarities, they are built on
totally disjoint object models - different ways to get at the same thing...

> Which is why you need an accessor to get at instance
> variables, since as variables they exist in the scope scope of the
> class, but they are not callable so they are not attributes of the
> instance.

I would certainly not define it that way, but anyway...

Yadda yadda.

> class A
> attr_accessor :a # == self.a,
> # accessible to instances of A
> def initialize
> @a = "foo" # A.__a
> # only accessible from class scope of A

First point, in Python, the name-mangling mechanism invoked by double
leading underscores doesn't make the attribute inaccessible from the
outside - it only requires you to use the mangled name.

Second point, defining a name in the class statement body makes it a
class attribute - while in in your Ruby example, what you define is an
instance attribute, and there's no class attribute involved.

> end
> end


> Once again, there is no such thing as an attribute that is not a
> method in ruby, and there is no such thing as setting an *attribute*
> ("=" is a method also).

What you mean here is that all Ruby's attributes are computed
attributes, at least when looked up from the outside. Nothing new here,
that's one of the first things one learns in Ruby.

As far as I'm concerned, I was not talking implementation here, but
semantic. It's quite obvious that Python and Ruby have totally different
implementations for what looks like the same thing and mostly share the
same semantic.

In your Ruby snippet, you show a class that defines a member variable
'@a' and a public r/w attribute 'a', the second giving access to the
first. I do hope we at least agree on this ?

Yes ?

Ok, so the exact *semantic* equivalent in Python is my first snippet -
that is, a plain attribute. It's *both* the member variable *and* the
public r/w attribute. Until you decide you want a computed attribute
instead, in which case - since Python has no distinct namespaces for
methods and attributes (I told you it didn't distinguished them,
remember ?) - you keep the public name 'a' for the (now computed)
attribute and you rename the member variable '_a' (which, in Python,
means "implementation part, don't touch").


> You're trying to *re-implement* rubys
> mechanism in python in your example, but in pythons mechanism, all
> attributes already have built-in getter/setter. So the correct analogy
> is a variable that is accessible from within the classes scope only
> (A.__a), and then exposed to instances through an attribute (self.a).

You may want to try your example with a list instead of a string, and
understand why your above proposition is nothing close to how things
work in Python. It may save you some pain debugging weird bugs later in
your Python code.

> Your example leaves out a variable accessible only from within the
> scope of the class, and adds a new attribute accessible from the
> instance (_a).

Do yourself a favour: Python's object model, scoping rules, lookup
mechanisms and name-mangling mechanisms are all well defined and
documented. So please *read* that documentation. Sorry but I don't feel
like rewriting the whole damn thing here for you !-)

>>>>>1.) I also found python's style of method referencing to be a lot more
>>>>>intuitive than using something like ruby's "m = method('foo');
>>>>>m.call('bar')" to get a reference to foo() and call it. It's alot
>>>>>cleaner to say "m = foo; m('bar')", imo. But this goes back to the
>>>>>omitting parens thing, which makes it impossible to do it that way in
>>>>>ruby.
>>
>>>>Yeps. This is where the real and fundamental difference between Ruby and
>>>>Python becomes evident. Both have support for transparent computed
>>>>attributes, but the way it's implemented is totally different - in Ruby,
>>>>by not having a call operator at all (I mean, the parens), in Python by
>>>>having both an explicit call operator and an explicit protocol for
>>>>computed attributes (the descriptor protocol). Not to say one is better
>>>>than the other, but that while both languages have similar features
>>>>(and, at first look, similar syntaxes), they really have totally
>>>>different object models.
>>
>>>Yes and no. I'll leave it at that. If you want to know more, do your
>>>homework. :P
>>
>>Hmmm... Sorry, but from this thread and another one here about the
>>distinction between attributes and method, I have the strong impression
>>you have more homework to do than me - at least wrt/ Python's object
>>model. May I suggest you take a look at the doc about the lookup
>>mechanism, the descriptor protocol and the call operator ?-)
>
>
> Sure. But as I understand, every attribute in python is a value, and
> some values are "tagged" as callable.

Nope. *Everything* in Python is an *object* (including modules, classes,
functions, and even the compiled code of the function), and some objects
implement the support for the call operator. No 'tag' here, this is done
just like any other operator overloading in Python - by defining the
appropriate method (here, '__call__').

> And this makes a distinction
> between attributes that are callable (methods) and attributes that are
> not.

This makes a distinction between *objects* that are callables and
objects that are not, yes. Just like, in Ruby, there's a distinction
between objects that supports the ':call' message and objects that dont.
BTW, can you define your own callable types in Ruby ?

Now here again, we use the same words with different definitions. No
surprise we have difficulties agreeing !-)

> In ruby there is no such thing as a non-callable attribute.

There's no such thing as a non *computed* attribute - to say it the
Python way !-) There are *of course* non-callable (Python way again)
attributes in Ruby : attributes that doesn't understand the :call message.

But what, even when we say "attributes", we don't mean exactly the same
thing !-)

> My
> comment was wrt saying that they both have "support for transparent
> computed attributes," since there is no computation of what kind of
> attribute it is on the ruby model

What I mean by "transparent computed attributes" is: something that
looks like a plain attribute access (Python's way), but is in fact
accessed thru accessors methods.

Ruby implement this by systematically going thru accessors, and
providing a shortcut for 'default' accessors (which is coherent with
it's message-passing semantic), while Python implements this by using
plain attribute (ie member variable) access as the default and providing
hooks into the lookup mechanism (__getattr__, __setattr__, and the
descriptor protocol on which the property class is based) so you can
customize it (the lookup mechanism) at will.

> Every attribute access is directly
> translatable into object.send(symbol).

While in Python, every attribute access is translatable into
getattr(object, name).

Ok, I think I get what you mean. But, well, it's just seems like
polymorphism at work to me.

regards,

Bruno Desthuilliers

unread,
Dec 9, 2007, 4:51:45 PM12/9/07
to
MonkeeSage a écrit :

> On Dec 9, 1:58 pm, MonkeeSage <MonkeeS...@gmail.com> wrote:
>
>
>> Sure. But as I understand, every attribute in python is a value,
>
>
> sorry...*references* a value
>
So make it: 'reference an object'

Bruno Desthuilliers

unread,
Dec 9, 2007, 4:59:07 PM12/9/07
to
Steve Howell a écrit :
(snip)

>
> Jordan and others, thanks for all your posts; I am
> learning a lot about both languages.
>
> This is what I've gathered so far.
>
> Python philosophy:
> passing around references to methods should be
> natural (i.e. my_binary_op = math.add)
> calling methods should be explicit (use parens)
> the use of setters/getters varies among Python
> programmers; properties, decorators, special methods,
> etc. can be used judiciously to affect the interface

You can forget decorators here - the examples in this thread were mostly
tricky ways to define properties. To be more general, the Python way to
implement transparent computed attributes is to hook into the lookup
mechanism, usually thru the descriptor protocol (the property class
being one possible implementation), but also using the __getattr__ /
__getattribute / __setattr__ hooks.

> Ruby philosophy:
> a method itself should be callable without parens
> you can get a reference to a chunk of code, but
> then you need a little extra syntax, beyond just a
> variable name and parens, to eventually call it
> (yield, &, call, etc.)
> when referring to methods, you can use :symbols to
> name the method you're interested in without actually
> calling it
>
> My personal experience:
>

(snip)


>
> I was surprised in Ruby by how seldom I really pass
> references to methods around,

This probably has to do with this nice feature named 'blocks' !-)

Steve Howell

unread,
Dec 9, 2007, 7:16:14 PM12/9/07
to Bruno Desthuilliers, pytho...@python.org

--- Bruno Desthuilliers
<bdesth.qu...@free.quelquepart.fr> wrote:

Ok, that makes sense.



> > Ruby philosophy:
> > a method itself should be callable without
> parens
> > you can get a reference to a chunk of code, but
> > then you need a little extra syntax, beyond just a
> > variable name and parens, to eventually call it
> > (yield, &, call, etc.)
> > when referring to methods, you can use :symbols
> to
> > name the method you're interested in without
> actually
> > calling it
> >
> > My personal experience:
> >
> (snip)
> >
> > I was surprised in Ruby by how seldom I really
> pass
> > references to methods around,
>
> This probably has to do with this nice feature named
> 'blocks' !-)
>

Partly. It's also due to the fact that my experience
so far in Ruby has mostly been writing code at the top
layer of a fairly vanilla Rails MVC app, whereas in
Python I've done a much wider variety of tasks.

MonkeeSage

unread,
Dec 9, 2007, 7:23:24 PM12/9/07
to
Hi Bruno,

I think that we've been having a mainly "semantic" (pun intended)
dispute. I think you're right, that we've been using the same words
with different meanings.

I would like to say firstly that I've been using python for a few
years now (about three I think), and I think I have a basic grasp of
the object system and so forth (e.g., I understood your example with
the apply decorator and properties). I read the docs when I first
started learning python (along with Fredrik Lundh's page about python
objects and more recently "call by object"). But I also own up to my
ignorance. I'm not a guru by any means. So you'll have to forgive me
if my ignorance has gotten in the way. I'll definitely re-read the
docs tonight.

I would like to (try to) clarify a little about my use of wording. By
"attribute" I was referring to a member of an object (*other than*
toplevel). I was of course using "method" to refer to callable
attributes (and I would use "function" for callable attributes bound
to toplevel), and I was using "variable" to refer to non-callable
attributes. By "tagging" I meant that attributes without a
"tag" (e.g., __call__) are not included in the MRO for an object; they
must be "tagged" as something other than a "variable".

As for ruby, I think the opcodes will help me clarify...

>> require 'parse_tree'
=> true
>> ParseTree.translate(%q{
class A
def foo
"bar"
end
end
A.new.foo
})
=> [:block, [:class, :A, nil, [:scope, [:defn, :foo, [:scope, [:block,
[:args], [:str, "bar"]]]]]], [:call, [:call,
[:const, :A], :new], :foo]]

Notice that #new and #foo are both CALL ops. All attribute access is
CALL (i.e., "method"). There really is no such thing as a non-callable
"attribute" in ruby. Within the scope of a class (block, &c), there
can be non-callable members of course (LVAL), but "foo" can mean
either LVAL *or* FCALL, because there is no "tagging", it's just
whatever is in context and/or parsed first as a given type of object
(well there are a few other rules, but that's the main idea), with
"()" is a hint to help the parser when the expression is ambiguous:

a = 1
def a; 2; end
a # [:lval :a] == a = 1
a() # [:fcall :a] == def ...

Given this, I see the addition the instance variable also being an
attribute as a *huge* difference between the ruby code and your
initial example. An attribute can be named the same as an lval and
return or set the value of the lval (e.g., @a), but it's no different
from any other method.

class A
def initialize; @a = "blah"; end
attr_reader :a
def cheese; @a; end # exactly equivalent
end

But at the same time, I can see how my python example can be seen as
*wildly* different (WTF?) as well. Maybe there is no easy way to
provide a true formally equivalent translation due to the
implementation differences of the languages (or if Saphir-Whorf is
right, maybe we just can't think of it! ;)

Anyhow, sorry for the confusion.

Regards,
Jordan

MonkeeSage

unread,
Dec 9, 2007, 7:39:14 PM12/9/07
to

Ps. To answer a question you asked, "callable" objects don't generally
implement a #call method--just Proc objects and method references
[class Method instances] do, which even though they have a #call
method, aren't usually considered "callable" since you can't call them
directly--the #call method could as easily be named #run or #evaluate
or whatever. Accessing a name in ruby basically does something like:
VCALL name (== if parens on name like a() skip to call step, otherwise
check for LVAL in scope and return value if found, otherwise FCALL/
CALL and return result). You can use the #define_method method to
create a new "callable."

Regards,
Jordan

Steve Howell

unread,
Dec 9, 2007, 8:26:55 PM12/9/07
to MonkeeSage, pytho...@python.org

--- MonkeeSage <Monke...@gmail.com> wrote:

> On Dec 9, 6:23 pm, MonkeeSage <MonkeeS...@gmail.com>
> wrote:
> > Hi Bruno,
> >
> > I think that we've been having a mainly "semantic"
> (pun intended)
> > dispute. I think you're right, that we've been
> using the same words
> > with different meanings.
> >

I think Ruby and Python have lots of false cognates,
or faux amis.

> >
> > But at the same time, I can see how my python
> example can be seen as
> > *wildly* different (WTF?) as well. Maybe there is
> no easy way to
> > provide a true formally equivalent translation due
> to the
> > implementation differences of the languages (or if
> Saphir-Whorf is
> > right, maybe we just can't think of it! ;)
> >

I think that there is an inherent difficulty in
translation here. To give a metaphor, it's
impossible, or at least very difficult, to explain, in
French, how certain English phrases translate to
French, without your French sounding a little English,
or just downright wrong. And vice versa.

Virgil Dupras

unread,
Dec 10, 2007, 3:36:59 AM12/10/07
to
On Dec 9, 1:15 am, Bruno Desthuilliers

I like Guido's proposal for read/write properties.
http://mail.python.org/pipermail/python-dev/2007-November/075182.html

It works pretty well and is readable.

Bruno Desthuilliers

unread,
Dec 10, 2007, 9:31:47 AM12/10/07
to
MonkeeSage a écrit :

> On Dec 9, 6:23 pm, MonkeeSage <MonkeeS...@gmail.com> wrote:
>> Hi Bruno,
>>
>> I think that we've been having a mainly "semantic" (pun intended)
>> dispute. I think you're right, that we've been using the same words
>> with different meanings.

Fine. So we may have a chance to get out there !-)

(snip)


>> I would like to (try to) clarify a little about my use of wording. By
>> "attribute" I was referring to a member of an object (*other than*
>> toplevel). I was of course using "method" to refer to callable
>> attributes (and I would use "function" for callable attributes bound
>> to toplevel), and I was using "variable" to refer to non-callable
>> attributes. By "tagging" I meant that attributes without a
>> "tag" (e.g., __call__) are not included in the MRO for an object; they
>> must be "tagged" as something other than a "variable".

Nope. We've been thru the distinction between a callable attribute and a
methodin another nearby thread, so won't come back on this. wrt/ mro,
it's being used for *all* attributes. That is, the look up rule for an
attribute is :

1. instance's __dict__
2. class's __dict__
3. all classes __dict__s in the class's mro

NB : not taking __getattribute__ and __getattr__ hooks into account here.

>> As for ruby, I think the opcodes will help me clarify...

Not for me, sorry - my time to deal with my own ignorance !-)

>>>> require 'parse_tree'
>> => true
>>>> ParseTree.translate(%q{
>> class A
>> def foo
>> "bar"
>> end
>> end
>> A.new.foo})
>>
>> => [:block, [:class, :A, nil, [:scope, [:defn, :foo, [:scope, [:block,
>> [:args], [:str, "bar"]]]]]], [:call, [:call,
>> [:const, :A], :new], :foo]]
>>
>> Notice that #new and #foo are both CALL ops. All attribute access is
>> CALL (i.e., "method"). There really is no such thing as a non-callable
>> "attribute" in ruby.

For a definition of attribute being different from 'member variable'.
But what we disagreed was more about the definitions of 'attribute' and
'callable' !-)

>> Given this, I see the addition the instance variable also being an
>> attribute as a *huge* difference between the ruby code and your
>> initial example. An attribute can be named the same as an lval and
>> return or set the value of the lval (e.g., @a), but it's no different
>> from any other method.

You still have both a member variable and an 'attribute'. And the member
variable is stored in the instance, while the 'attribute' (that is, the
getter and setter methods) are stored with the class. From this POV,
this is the equivalent of the Python snippet using a property.

>> But at the same time, I can see how my python example can be seen as
>> *wildly* different (WTF?) as well.

The WTF was about the class attribute. Did you try it with a mutable
object instead of a string, and more than one instance ?-)

>> Maybe there is no easy way to
>> provide a true formally equivalent translation due to the
>> implementation differences of the languages

That's why I think the important point here is the semantic, not the
implementation (while talking about the method/non-method distinction in
Python is clearly about implementation).

>> Anyhow, sorry for the confusion.

You don't have to be sorry. We're both guilty (if guilty of anything)
and honestly, I tend to be a bit on the nit-pick side, which sometimes
doesn't help.

> Ps. To answer a question you asked, "callable" objects don't generally
> implement a #call method--just Proc objects and method references
> [class Method instances] do, which even though they have a #call
> method, aren't usually considered "callable" since you can't call them
> directly--the #call method could as easily be named #run or #evaluate
> or whatever. Accessing a name in ruby basically does something like:
> VCALL name (== if parens on name like a() skip to call step, otherwise
> check for LVAL in scope and return value if found, otherwise FCALL/
> CALL and return result). You can use the #define_method method to
> create a new "callable."

Thanks for the precisions.

regards,

Chris Mellon

unread,
Dec 10, 2007, 11:14:41 AM12/10/07
to pytho...@python.org


Something very like this will be in 3k, and I believe is also being
backported to 2.6. See python-dev archives for more.

Lou Pecora

unread,
Dec 11, 2007, 1:39:25 PM12/11/07
to
In article <475c37ef$0$11450$426a...@news.free.fr>,
Bruno Desthuilliers <bdesth.qu...@free.quelquepart.fr> wrote:

> Lou Pecora a écrit :
> > In article <475ae612$0$645$426a...@news.free.fr>,
> > Bruno Desthuilliers <bdesth.qu...@free.quelquepart.fr> wrote:
> >
> >
> >>>Thus: close;
> >>>could replace close();
>
> *Please* give proper attribution. I'd *never* suggest such a thing.

I apologize.

--
-- Lou Pecora

0 new messages