Confessions of a Python fanboy

102 views
Skip to first unread message

r

unread,
Jul 29, 2009, 11:06:33 PM7/29/09
to

Hello fellow Pythonista's it's nice to be back after such a long
hiatus. I have recently realized my blind love affair with Python was
just that. I must admit there are better ways to program. Like your
first lay, your first programing language can leave an indelible mark
on you, but like all young chaps, the passion for programming has
sweep me away into vast new orgies of programming bliss. (ig ,little
head guides the big one.)

My adventures in Ruby.
an autobyography by rt8396

After breaking free from the wild love affair i had with Python, a new
day had dawned. I dried my eyes and soon discovered the Ruby language
(not by choice however) --now don't worry fellow Pythonistas, i am
still on your side (mostly) -- but i now realize Ruby has some good
things going for it. For instance...

1.) No need to use "()" to call a function with no arguments.
Python --> "obj.m2().m3()" --ugly
Ruby --> "obj.m1.m2.m3" -- sweeet!
Man, i must admit i really like this, and your code will look so much
cleaner.

2.) the .each method
container.each{|localVar| block}
This method can really cleanup some ugly for loops, although i really
like the readability of for loops.

3.) true OOP
Now before you go and get all "huffy" over this statement, hear me
out. Python is the best language in the world. But it damn sure has
some warts! "len(this)" instead of "obj.length" max(that) instead of
[1,2,3,4,5].max(). You know what i am talking about here people. We
all get complacent and It seems easier to just cope with these
problems instead of fighting for change. But look at the French, WHAT
THE HELL HAS THAT DONE FOR THEM, *NOTHING*!!!!

As for the rest of Ruby, i am not impressed. The redundant usage of
"end" over indention perplexes me. The Perlish feel of "require" and
the horrifically cryptic idioms of Ruby regular expressions. The
"puts" and "gets" seem childish and the math class does not even have
a degrees or radians function!

Anyway, i thought i would get this off my chest and catch up with old
friends in the meantime. We can all make Python the perfect language
it needs to be, but it ain't gonna be easy!
Thank you all

PS stay tuned for more from this series....


alex23

unread,
Jul 30, 2009, 12:04:27 AM7/30/09
to
On Jul 30, 1:06 pm, r <rt8...@gmail.com> wrote:
> 1.) No need to use "()" to call a function with no arguments.
> Python --> "obj.m2().m3()" --ugly
>   Ruby --> "obj.m1.m2.m3"  -- sweeet!
> Man, i must admit i really like this, and your code will look so much
> cleaner.

How do you distinguish between calling a method with no arguments, and
getting access to the method object itself (because it _is_ an object,
y'know, it's OO all the way down...)?

> 2.) the .each method
> container.each{|localVar| block}
> This method can really cleanup some ugly for loops, although i really
> like the readability of for loops.

map(lambda localVar: <block>, sequence)

or:

def usefully_named_func(var):
<block>
return var

transformed = [usefully_named_func(v) for v in sequence]

> 3.) true OOP
> Now before you go and get all "huffy" over this statement, hear me
> out. Python is the best language in the world. But it damn sure has
> some warts! "len(this)" instead of "obj.length" max(that) instead of
> [1,2,3,4,5].max().

As the Zen says: '[P]racticality beats purity'. Personally, I'm not
sure how a handful of convenient built-in functions make a language in
which _everything is an object_ somehow "false" OO.

If you're really that concerned with writing "true" OO (for some
wildly variable value of "true"), there's nothing stopping you from
doing so now:

obj.__len__()

With max(), this is a built-in that takes _any_ iterable and an
optional key function, and returns the highest value as per the key.
This means that _every_ iterable object - as _well_ as every object
that supports enough of the iterator protocol - can be handed to max()
and a result obtained. So at best, I just need to make sure my new
sequence-type provides the iterator protocol and viola, it works with
max() without me having to hand-code a .max() that's specialised for
my new type, and without Python forcing me to have a complex
inheritance chain just to make sure I include the right
MaxableSequence ancestor to inherit the right .max().

> PS stay tuned for more from this series....

Is this going to be more of you telling us - without any apparent
irony whatsoever - how Ruby has some valid points after all your
vilification last year when we said the same to you? If so, where can
I sign up?!

(You should consider trading guest spot posts with Xah Lee on your
respective blogs. You both have a very similar approach to programming
& programming languages and I think the synergy would be amazing to
see.)

Chris Rebert

unread,
Jul 30, 2009, 12:27:20 AM7/30/09
to alex23, pytho...@python.org
On Wed, Jul 29, 2009 at 9:04 PM, alex23<wuw...@gmail.com> wrote:
> On Jul 30, 1:06 pm, r <rt8...@gmail.com> wrote:
>> 1.) No need to use "()" to call a function with no arguments.
>> Python --> "obj.m2().m3()" --ugly
>>   Ruby --> "obj.m1.m2.m3"  -- sweeet!
>> Man, i must admit i really like this, and your code will look so much
>> cleaner.
>
> How do you distinguish between calling a method with no arguments, and
> getting access to the method object itself (because it _is_ an object,
> y'know, it's OO all the way down...)?

IIRC from the Pickaxe, to get at a method object, you call a method on
the object whose specific job it is to return method objects.
Unsurprisingly, this method is itself named "method". So:

foo.bar #calls the "bar" method on foo
foo.method(:bar) #returns the method "bar" of foo, as an object

Cheers,
Chris
--
http://blog.rebertia.com

Carl Banks

unread,
Jul 30, 2009, 12:43:47 AM7/30/09
to

Here is some wisdom from Guido van Rossum on the matter:

http://mail.python.org/pipermail/python-dev/2006-May/064841.html


Carl Banks

Marco Mariani

unread,
Jul 30, 2009, 6:29:50 AM7/30/09
to
r wrote:

> My adventures in Ruby.

Oh, it's you.
Good boy.
Now, why don't you have a look at javascript and come back in six months?
Or better yet, haskell and twelve months.

thanks

Masklinn

unread,
Jul 30, 2009, 7:36:49 AM7/30/09
to pytho...@python.org
On 30 Jul 2009, at 06:04 , alex23 wrote:
> On Jul 30, 1:06 pm, r <rt8...@gmail.com> wrote:
>> 1.) No need to use "()" to call a function with no arguments.
>> Python --> "obj.m2().m3()" --ugly
>> Ruby --> "obj.m1.m2.m3" -- sweeet!
>> Man, i must admit i really like this, and your code will look so much
>> cleaner.
>
> How do you distinguish between calling a method with no arguments, and
> getting access to the method object itself (because it _is_ an object,
> y'know, it's OO all the way down...)?
>
As chris pointed out, there's a method for that, to which a symbol is
provided: `Object#method(methodname)`, which is basically equivalent
to `getattr(object, methodname)` in Python.

>> 2.) the .each method
>> container.each{|localVar| block}
>> This method can really cleanup some ugly for loops, although i really
>> like the readability of for loops.
>
> map(lambda localVar: <block>, sequence)
>
> or:
>
> def usefully_named_func(var):
> <block>
> return var
>
> transformed = [usefully_named_func(v) for v in sequence]
>

The issue here is of course that `map` and comprehensions are
transformations. `#each` exists for effectful iterations (Ruby has
`#map` for the map operation). So the intent expressed by `#each` and
`map` isn't the same. Furthermore and this is the most problematic
limitation of Python here, `lambda` doesn't allow complex
transformations due to its restrictions, so one has to switch to named
functions which works but isn't sexy (and tends to lower readability
imo).

>> 3.) true OOP
>> Now before you go and get all "huffy" over this statement, hear me
>> out. Python is the best language in the world. But it damn sure has
>> some warts! "len(this)" instead of "obj.length" max(that) instead of
>> [1,2,3,4,5].max().
>
> As the Zen says: '[P]racticality beats purity'. Personally, I'm not
> sure how a handful of convenient built-in functions make a language in
> which _everything is an object_ somehow "false" OO.
>

That's an interesting point, but not relevant at the end of the day:
`foo.length` and `length(foo)` have the same "practicality". On the
other hand Ruby can be praised for the coherence: everything's a
method period end of the story; while Python does have a dichotomy
between methods and functions/generic methods (whether or not that
dichotomy bothers users is another issue).

> With max(), this is a built-in that takes _any_ iterable and an
> optional key function, and returns the highest value as per the key.
> This means that _every_ iterable object - as _well_ as every object
> that supports enough of the iterator protocol - can be handed to max()
> and a result obtained. So at best, I just need to make sure my new
> sequence-type provides the iterator protocol and viola, it works with
> max() without me having to hand-code a .max() that's specialised for
> my new type, and without Python forcing me to have a complex
> inheritance chain just to make sure I include the right
> MaxableSequence ancestor to inherit the right .max().
>

Well interestingly, Ruby works pretty much the same way. Where Python
asks that you implement the iterator protocol to have `max` work, Ruby
asks that you implement the `each` method (also called the Enumerable
protocol) and mixin `Enumerable` (http://ruby-doc.org/core/classes/Enumerable.html
). Then you get max (and min, map, etc…) "for free". Of course you're
free to re-implement all of them manually if you wish to do so (or if
you need those operations to return your custom collection rather than
arrays). Enumerable is merely a convenience mixin. So there's no big
difference here (and note that mixins aren't necessarily part of the
inheritance chain, though they're implemented that way in Ruby).

Also, it's "voilà" not "viola" (a viola is a bowed string instrument,
slightly bigger than a violin, whereas voilà is a french interjection
used to call attention or suggest the appearance of something, as if
by magic).

>> PS stay tuned for more from this series....
>
> Is this going to be more of you telling us - without any apparent
> irony whatsoever - how Ruby has some valid points after all your
> vilification last year when we said the same to you? If so, where can
> I sign up?!

I fear I'll have to agree with that sentiment.

superpollo

unread,
Jul 30, 2009, 8:03:38 AM7/30/09
to
Masklinn wrote:
...

> That's an interesting point, but not relevant at the end of the day:
> `foo.length` and `length(foo)` have the same "practicality". On the
> other hand Ruby can be praised for the coherence: everything's a method
> period end of the story; while Python does have a dichotomy between
> methods and functions/generic methods (whether or not that dichotomy
> bothers users is another issue).
...
how would you correct a newbie (like me) who says:

"well, the main difference between a function and a method (from the
caller's pow) is a syntactic one:

fun(obj, arguments)

as opposed to:

obj.met(arguments)

but the effect is just about the same."

?

bye

Jean-Michel Pichavant

unread,
Jul 30, 2009, 8:24:39 AM7/30/09
to superpollo, pytho...@python.org

My suggestion

- OO programming:
length(foo) calls the foo instance(or class for some language) length method
length(bar) calls the bar instance length method, it is **not** the same
than the foo method

- non OO programming:
length(foo) calls the length function with foo as parameter
length(bar) calls the **same** length function with the bar parameter
(so you better make sure length is handling both foo and bar)

So the difference is definitely **not** a syntactic one, but it is true
that the syntax obj.method() better illustrates the bind mechanism of
the OO programming.

JM

Masklinn

unread,
Jul 30, 2009, 8:30:48 AM7/30/09
to pytho...@python.org
Depending on the way things are implemented, it can be very similar
(see CLOS' generic functions, which have the same look as functions
but dispatch based on parameter types).

In Python, the difference would be that functions don't automatically
dispatch (you have a function for everybody, and any dispatch you
perform based on argument types or other qualifiers has to be done
manually) whereas methods do dispatch on the first [implied] argument
(you execute a precise method corresponding to the object it's being
called on).

So fun(obj, *arguments) will call the same `fun` whether `obj` is an
int, a string or an HTTPFactory whereas obj.met(*arguments) will call
a different `met` each time (they all have the same "unqualified" name
[and signature if it's part of a protocol], but might very well be
implemented completely differently). Therefore -- in python -- the
effect isn't anywhere "just about the same".

Colin J. Williams

unread,
Jul 30, 2009, 12:18:07 PM7/30/09
to
Some have treated this as a troll. I don't.
r wrote:
[snip]

> 1.) No need to use "()" to call a function with no arguments.
> Python --> "obj.m2().m3()" --ugly
> Ruby --> "obj.m1.m2.m3" -- sweeet!
> Man, i must admit i really like this, and your code will look so much
> cleaner.
>

+1


> 2.) the .each method
> container.each{|localVar| block}
> This method can really cleanup some ugly for loops, although i really
> like the readability of for loops.
>

Not clear.


> 3.) true OOP
> Now before you go and get all "huffy" over this statement, hear me
> out. Python is the best language in the world. But it damn sure has
> some warts! "len(this)" instead of "obj.length" max(that) instead of
> [1,2,3,4,5].max(). You know what i am talking about here people. We
> all get complacent and It seems easier to just cope with these
> problems instead of fighting for change. But look at the French, WHAT
> THE HELL HAS THAT DONE FOR THEM, *NOTHING*!!!!
>

+0.6
or better [1, 2, 3, 4, 5].len or [1, 2, 3, 4, 5].max

What has this got to do with "true OOP"?

[snip]

Falcolas

unread,
Jul 30, 2009, 12:31:22 PM7/30/09
to
On Jul 29, 9:06 pm, r <rt8...@gmail.com> wrote:

> 1.) No need to use "()" to call a function with no arguments.
> Python --> "obj.m2().m3()" --ugly
>   Ruby --> "obj.m1.m2.m3"  -- sweeet!
> Man, i must admit i really like this, and your code will look so much
> cleaner.

I personally would not prefer this, and would likely continue to use
(), precisely for code clarity - let me explain:

foo.nextval
foo.val
foo.previousval

Which of the calls above referenced instance variables, and which ones
called functions which changed the internal state of foo? I would have
trouble saying, just based on the calls above. I would have to go back
to the definition or documentation of foo to identify which is doing
what. On the other hand, the following gives a better clue as to what
is happening (granted not perfect, but better):

foo.nextval()
foo.val
foo.previousval()

~G

Inky 788

unread,
Jul 30, 2009, 1:01:40 PM7/30/09
to
On Jul 30, 12:04 am, alex23 <wuwe...@gmail.com> wrote:
> On Jul 30, 1:06 pm, r <rt8...@gmail.com> wrote:
>
> > 1.) No need to use "()" to call a function with no arguments.
> > Python --> "obj.m2().m3()" --ugly
> >   Ruby --> "obj.m1.m2.m3"  -- sweeet!
> > Man, i must admit i really like this, and your code will look so much
> > cleaner.
>
> How do you distinguish between calling a method with no arguments, and
> getting access to the method object itself (because it _is_ an object,
> y'know, it's OO all the way down...)?

I agree with alex here. Will take the explicit syntax over the extra
cognitive load of figuring out exactly what's going on with
`obj.m1.m2.m3`.

Python has its warts, but requiring ()'s on function calls isn't one
of them. :)

r

unread,
Jul 30, 2009, 1:09:02 PM7/30/09
to

I held your exact same view before i learned the Ruby language. And
your veiw makes some good points, however, naming conventions with
eliminate this problem all together. All "method names" should use the
underscore to separate words, "variable names" should use camelCase,
"constants" in all caps, and "class defs" in titlecase.

def go_and_do_this_for_me_now(self, *args)
self.variableNameHere
MyClassNameHere
THISISACONSTANT -or- THIS_IS_A_CONSTANT


in your example i would have used the following

foo.next_value
foo.value
foo.prev_value

good naming conventions will make your life (and everybody else's)
much easier when debugging code.

Masklinn

unread,
Jul 30, 2009, 1:10:35 PM7/30/09
to pytho...@python.org
On 30 Jul 2009, at 18:31 , Falcolas wrote:
> On Jul 29, 9:06 pm, r <rt8...@gmail.com> wrote:
>
>> 1.) No need to use "()" to call a function with no arguments.
>> Python --> "obj.m2().m3()" --ugly
>> Ruby --> "obj.m1.m2.m3" -- sweeet!
>> Man, i must admit i really like this, and your code will look so much
>> cleaner.
>
> I personally would not prefer this, and would likely continue to use
> (), precisely for code clarity - let me explain:
>
> foo.nextval
> foo.val
> foo.previousval
>
> Which of the calls above referenced instance variables
Well, that's very simple: none of them. In Ruby (as in Smalltalk),
public instance variables simply don't exist.

> and which ones called functions which changed the internal state of
> foo?

That you can't say, but neither can you say in Python as they could
all be properties. And of course just because it's a method doesn't
mean it mutates the object.

> I would have
> trouble saying, just based on the calls above. I would have to go back
> to the definition or documentation of foo to identify which is doing
> what. On the other hand, the following gives a better clue as to what
> is happening (granted not perfect, but better):

Well... it doesn't give much of a clue no really.

Masklinn

unread,
Jul 30, 2009, 1:15:14 PM7/30/09
to Inky 788, pytho...@python.org
On 30 Jul 2009, at 19:01 , Inky 788 wrote:
> On Jul 30, 12:04 am, alex23 <wuwe...@gmail.com> wrote:
>> On Jul 30, 1:06 pm, r <rt8...@gmail.com> wrote:
>>
>>> 1.) No need to use "()" to call a function with no arguments.
>>> Python --> "obj.m2().m3()" --ugly
>>> Ruby --> "obj.m1.m2.m3" -- sweeet!
>>> Man, i must admit i really like this, and your code will look so
>>> much
>>> cleaner.
>>
>> How do you distinguish between calling a method with no arguments,
>> and
>> getting access to the method object itself (because it _is_ an
>> object,
>> y'know, it's OO all the way down...)?
>
> I agree with alex here. Will take the explicit syntax over the extra
> cognitive load of figuring out exactly what's going on with
> `obj.m1.m2.m3`.
There's no cognitive load whatsoever: it's calling methods. Always.
Ruby simply gives you no other option. Now it could be very simple
methods to instance attributes, akin to a java getter, but it's still
only methods.

Furthermore Ruby has a pretty nice convention (sadly not used enough I
think) taken from Scheme where it's possible to postfix a method name
with "!" (note: the "!" is part of the name, there's no magic) to
indicate that this method modifies the object it's called on rather
than simply returning stuff.

r

unread,
Jul 30, 2009, 1:28:44 PM7/30/09
to
On Jul 30, 12:15 pm, Masklinn <maskl...@masklinn.net> wrote:
[snip]

> Furthermore Ruby has a pretty nice convention (sadly not used enough I  
> think) taken from Scheme where it's possible to postfix a method name  
> with "!" (note: the "!" is part of the name, there's no magic) to  
> indicate that this method modifies the object it's called on rather  
> than simply returning stuff.

Another oddity i did not like at first but must admit is growing on me
vector.reverse --> returns a new reversed vector
vector.reverse! --> modifies the instance vector in-place

Of course in python you would do...
vector.reverse --> in-place
vector.reversed --> in-place

The above example works pretty good, but this doesn't always "sound"
good. Take for example this...
point3d.offset --> return a new pt
point3d.offseted --> What did you say!?!?!

Now try Ruby's way
point3d.offset!
point3d.offset

a symbol works better for these things

r

unread,
Jul 30, 2009, 1:33:38 PM7/30/09
to
Traceback (most recent post last):
File "<Confessions of a Python Fanboy>", lines (13,14), in <post>

vector.reverse --> in-place
vector.reversed --> in-place
DumbMistakeError:

Of course in python you would do...
vector.reverse --> in-place

vector.reversed --> new vector

Jean-Michel Pichavant

unread,
Jul 30, 2009, 1:37:00 PM7/30/09
to r, pytho...@python.org
How do I know if foo.value is an attribute or if it is a method that
returns the foo value ? It seems you can make the difference only when
tokens are composed of more than one word, not very handy don't you think ?

Just feeding the troll.

JM

r

unread,
Jul 30, 2009, 1:45:49 PM7/30/09
to
On Jul 30, 12:37 pm, Jean-Michel Pichavant <jeanmic...@sequans.com>
wrote:

You can still use empty parenthesis in Ruby if that floats your boat.

obj.method() <-- note the empty parenthesis

I am just saying don't make them mandatory, thats all. In any case
where ambiguity abounds, by all means use the damn parenthisis.

Now Ruby will even let you call a method *that has arguments* with no
parenthisis -- however, i do not think this is a good idea. Consider
the following

Geom::Transformation.rotation pt, vec, ang
bad coder!, bad!
...and leads to worn out eyeball parsers in a hurry

Geom::Transformation.rotation(pt, vec, ang)
yes, good boy!


Carsten Haese

unread,
Jul 30, 2009, 1:42:30 PM7/30/09
to pytho...@python.org
r wrote:
> Of course in python you would do...
> vector.reverse --> in-place
> vector.reversed --> in-place

You do know that only one of those works in-place, right?

> The above example works pretty good, but this doesn't always "sound"
> good. Take for example this...
> point3d.offset --> return a new pt
> point3d.offseted --> What did you say!?!?!
>
> Now try Ruby's way
> point3d.offset!
> point3d.offset
>
> a symbol works better for these things

Or you could use a better verb:

point3d.move -> modifies in place
point3d.moved -> returns a new point

-Carsten

Tim Rowe

unread,
Jul 30, 2009, 1:47:04 PM7/30/09
to pytho...@python.org
2009/7/30 r <rt8...@gmail.com>:

>
> Like your
> first lay, your first programing language can leave an indelible mark
> on you

That's true. FOCAL scarred me for life.

> but i now realize Ruby has some good
> things going for it.

Any language that gets any sort of real use has to have. For instance,
I love Ada's numeric types (you can specify either the minimum number
of significant figures or the maximum delta for a real type, and it
will give you a type that satisfies that -- or a compilation error if
it can't. That matches genuine problem domains far better than having
to remember how many bits in a double on this particular system, and
reduces portability bugs).

> 3.) true OOP
> Now before you go and get all "huffy" over this statement, hear me
> out. Python is the best language in the world. But it damn sure has
> some warts! "len(this)" instead of "obj.length" max(that) instead of
> [1,2,3,4,5].max(). You know what i am talking about here people. We
> all get complacent and It seems easier to just cope with these
> problems instead of fighting for change. But look at the French,  WHAT
> THE HELL HAS THAT DONE FOR THEM, *NOTHING*!!!!

I seem to recall recent studies showing that the French were on
average happier than Brits or Americans. Don't knock it!

> As for the rest of Ruby, i am not impressed. The redundant usage of
> "end" over indention perplexes me. The Perlish feel of "require" and
> the horrifically cryptic idioms of Ruby regular expressions. The
> "puts" and "gets" seem childish and the math class does not even have
> a degrees or radians function!

The operating system dependency built into the language did it for me.
That and the fact that I couldn't stop laughing for long enough to
learn any more when I read in the Pragmatic Programmer's Guide that
"Ruby, unlike less flexible languages, lets you alter the value of a
constant." Yep, as they say "Bug" = "Undocumented feature"!

--
Tim Rowe

Masklinn

unread,
Jul 30, 2009, 1:56:07 PM7/30/09
to pytho...@python.org
On 30 Jul 2009, at 19:37 , Jean-Michel Pichavant wrote:
> How do I know if foo.value is an attribute or if it is a method that
> returns the foo value ?
It cannot be an attribute. Ruby doesn't give access to attributes,
they're always solely private (as in Smalltalk). Also you shouldn't
reply to r, he has no idea about what he's talking about.

Masklinn

unread,
Jul 30, 2009, 1:57:54 PM7/30/09
to pytho...@python.org
On 30 Jul 2009, at 19:42 , Carsten Haese wrote:

> r wrote:
>> Of course in python you would do...
>> vector.reverse --> in-place
>> vector.reversed --> in-place
>
> You do know that only one of those works in-place, right?
>
Well mostly because the other one doesn't exist (as python has
`lst.reverse()` but `reversed(lst)`) but he was probably talking
hypothetically. Or something.

superpollo

unread,
Jul 30, 2009, 2:05:53 PM7/30/09
to
r wrote:
> On Jul 30, 12:15 pm, Masklinn <maskl...@masklinn.net> wrote:
> [snip]
>
>>Furthermore Ruby has a pretty nice convention (sadly not used enough I
>>think) taken from Scheme where it's possible to postfix a method name
>>with "!" (note: the "!" is part of the name, there's no magic) to
>>indicate that this method modifies the object it's called on rather
>>than simply returning stuff.
>
>
> Another oddity i did not like at first but must admit is growing on me
> vector.reverse --> returns a new reversed vector
> vector.reverse! --> modifies the instance vector in-place
>
> Of course in python you would do...
> vector.reverse --> in-place
> vector.reversed --> in-place
>

how to reverse a string in python? must i usa a temp? like:

>>> s = "ciccio"
>>> l = list(s)
>>> l.reverse()
>>> s = "".join(l)
>>> s
'oiccic'
>>>

???

bye

Falcolas

unread,
Jul 30, 2009, 2:06:33 PM7/30/09
to

That doesn't sound like a feature I would appreciate much, though I am
a big fan of "we're all adults here" programming. Though if they are
all functions, then adding parentheses wouldn't make much difference,
so offering the option of getting rid of them makes sense.

>> I would have
>> trouble saying, just based on the calls above. I would have to go back
>> to the definition or documentation of foo to identify which is doing
>> what. On the other hand, the following gives a better clue as to what
>> is happening (granted not perfect, but better):

> Well... it doesn't give much of a clue no really.

It, with few exceptions, tells me that fetching the value foo.val will
not modify the state of foo. Important stuff, at least to me.

superpollo

unread,
Jul 30, 2009, 2:08:36 PM7/30/09
to
Tim Rowe wrote:
> 2009/7/30 r <rt8...@gmail.com>:
>
>>Like your
>>first lay, your first programing language can leave an indelible mark
>>on you
>
>
> That's true. FOCAL scarred me for life.
>
>
>>but i now realize Ruby has some good
>>things going for it.
>
>
> Any language that gets any sort of real use has to have. For instance,
> I love Ada's numeric types (you can specify either the minimum number
> of significant figures or the maximum delta for a real type, and it
> will give you a type that satisfies that -- or a compilation error if
> it can't. That matches genuine problem domains far better

doesn't the decimal module do some of that too?

bye

MRAB

unread,
Jul 30, 2009, 2:20:11 PM7/30/09
to pytho...@python.org
Use slicing with a step of -1:

>>> s = "ciccio"
>>> s[::-1]
'oiccic'

Masklinn

unread,
Jul 30, 2009, 2:22:21 PM7/30/09
to pytho...@python.org

s = s[::-1]

Masklinn

unread,
Jul 30, 2009, 2:24:23 PM7/30/09
to Falcolas, pytho...@python.org
On 30 Jul 2009, at 20:06 , Falcolas wrote:
> On Jul 30, 11:56 am, Masklinn <maskl...@masklinn.net> wrote:
>> On 30 Jul 2009, at 19:37 , Jean-Michel Pichavant wrote:
>>
>>> r wrote:
>
>>> How do I know if foo.value is an attribute or if it is a method that
>>> returns the foo value ?
>>
>> It cannot be an attribute. Ruby doesn't give access to attributes,
>> they're always solely private (as in Smalltalk). Also you shouldn't
>> reply to r, he has no idea about what he's talking about.
>
> That doesn't sound like a feature I would appreciate much, though I am
> a big fan of "we're all adults here" programming. Though if they are
> all functions, then adding parentheses wouldn't make much difference,
> so offering the option of getting rid of them makes sense.
>
That's pretty much it.

>>> I would have
>>> trouble saying, just based on the calls above. I would have to go
>>> back
>>> to the definition or documentation of foo to identify which is doing
>>> what. On the other hand, the following gives a better clue as to
>>> what
>>> is happening (granted not perfect, but better):
>
>> Well... it doesn't give much of a clue no really.
>
> It, with few exceptions, tells me that fetching the value foo.val will
> not modify the state of foo. Important stuff, at least to me.

But because of those few exceptions, it really tells you that foo.val
*probably* doesn't modify the state of foo. Unless you go source-
diving, you can't know for sure. Only Haskell gives you that kind of
guarantees (and even then, the code you call could have an unsafe*
somewhere)

Dave Angel

unread,
Jul 30, 2009, 2:28:11 PM7/30/09
to superpollo, pytho...@python.org
superpollo wrote:
>> <snip>

>
> how to reverse a string in python? must i usa a temp? like:
>
> >>> s = "ciccio"
> >>> l = list(s)
> >>> l.reverse()
> >>> s = "".join(l)
> >>> s
> 'oiccic'
> >>>
>
> ???
>
> bye
>
>
> </div>
>
simply s = s[::-1]

DaveA

superpollo

unread,
Jul 30, 2009, 2:30:45 PM7/30/09
to
MRAB wrote:
> superpollo wrote:
...

>> how to reverse a string in python? must i usa a temp? like:
>>
>> >>> s = "ciccio"
>> >>> l = list(s)
>> >>> l.reverse()
>> >>> s = "".join(l)
>> >>> s
>> 'oiccic'
>> >>>
>>
>> ???
>>
> Use slicing with a step of -1:
>
> >>> s = "ciccio"
> >>> s[::-1]
> 'oiccic'

lol

bye

Jan Kaliszewski

unread,
Jul 30, 2009, 4:23:32 PM7/30/09
to Masklinn, pytho...@python.org
30-07-2009 o 13:36:49 Masklinn <mask...@masklinn.net> wrote:

> On 30 Jul 2009, at 06:04 , alex23 wrote:


>> On Jul 30, 1:06 pm, r <rt8...@gmail.com> wrote:
>>> 2.) the .each method
>>> container.each{|localVar| block}
>>> This method can really cleanup some ugly for loops, although i really
>>> like the readability of for loops.
>>

>> map(lambda localVar: <block>, sequence)
>>
>> or:
>>
>> def usefully_named_func(var):
>> <block>
>> return var
>>
>> transformed = [usefully_named_func(v) for v in sequence]
>>
> The issue here is of course that `map` and comprehensions are
> transformations. `#each` exists for effectful iterations (Ruby has
> `#map` for the map operation). So the intent expressed by `#each` and
> `map` isn't the same. Furthermore and this is the most problematic
> limitation of Python here, `lambda` doesn't allow complex
> transformations due to its restrictions, so one has to switch to named
> functions which works but isn't sexy (and tends to lower readability
> imo).

I don't see any real limitation. What's wrong in:

for localVar in container:
block

And ruby's container.each is very similar to Python's iter()

*j

--
Jan Kaliszewski (zuo) <z...@chopin.edu.pl>

Masklinn

unread,
Jul 30, 2009, 4:41:57 PM7/30/09
to Jan Kaliszewski, pytho...@python.org
Well what's wrong with using that rather than `map`, `filter` or a
list comprehension? (and if you don't see what the limitations of
`lambda` are, you probably very rarely use it)

> And ruby's container.each is very similar to Python's iter()
>

Uh… not at all…

Terry Reedy

unread,
Jul 30, 2009, 4:55:17 PM7/30/09
to pytho...@python.org
superpollo wrote:
> r wrote:

> how to reverse a string in python? must i usa a temp? like:
>
> >>> s = "ciccio"
> >>> l = list(s)
> >>> l.reverse()
> >>> s = "".join(l)
> >>> s
> 'oiccic'
> >>>
>
> ???

No.
>>> ''.join(list(reversed('abc')))
'cba'
>>> 'abc'[2::-1]
'cba'
>>> 'abc'[1000000000::-1]
'cba'

Any int >= len(string)-1 will do, so the call to len will usually not be
necessary.

Needing strings reversed is not common. More common might be

for char in reversed(somestring): process(char)

Terry Jan Reedy

r

unread,
Jul 30, 2009, 5:02:03 PM7/30/09
to
On Jul 30, 3:55 pm, Terry Reedy <tjre...@udel.edu> wrote:
> superpollo wrote:
> > r wrote:
> > how to reverse a string in python? must i usa a temp? like:
[snip]
> Terry Jan Reedy

No "r" never wrote anything like that. reversing a string is RTFM
material, this is basic stuff here! Stop quoting me as saying things i
did not say! I never asked how to reverse a string, "superpollo"
did.

Emmanuel Surleau

unread,
Jul 30, 2009, 5:29:21 PM7/30/09
to pytho...@python.org
> 1.) No need to use "()" to call a function with no arguments.
> Python --> "obj.m2().m3()" --ugly
> Ruby --> "obj.m1.m2.m3" -- sweeet!
> Man, i must admit i really like this, and your code will look so much
> cleaner.

It has benefits - code does look better. It has also significant cons - it is
ambiguous.
For instance:

a = b

Is b a variable or a method called without parameter?

> 2.) the .each method
> container.each{|localVar| block}
> This method can really cleanup some ugly for loops, although i really
> like the readability of for loops.

It's not only the 'each' method. It's "anonymous callbacks everywhere", which
is pretty cool. Certainly one of my favourite features of Ruby.

> 3.) true OOP
> Now before you go and get all "huffy" over this statement, hear me
> out. Python is the best language in the world. But it damn sure has
> some warts! "len(this)" instead of "obj.length" max(that) instead of
> [1,2,3,4,5].max(). You know what i am talking about here people. We
> all get complacent and It seems easier to just cope with these
> problems instead of fighting for change.

While ob.length() is more clear to read, it follows the same "operator" logic
as __iter__. Which is OK, I suppose.

> But look at the French, WHAT
> THE HELL HAS THAT DONE FOR THEM, *NOTHING*!!!!

I assume this was supposed to be funny?

> As for the rest of Ruby, i am not impressed. The redundant usage of
> "end" over indention perplexes me.

You have the choice to use {}. If you are confused over languages which do not
use indentation to delimit code blocks, you should probably try out a few
languages outside Python.

> The Perlish feel of "require" and
> the horrifically cryptic idioms of Ruby regular expressions.

Cryptic idioms of Ruby regular expressions? They are Perl-like regular
expressions, not exactly a far cry from what re does. Also, you can chain
them, which is extremely nice.

> The "puts" and "gets" seem childish

Well, they're short and easy. Writing "gets" is more intuitive than using
raw_input()

> and the math class does not even have
> a degrees or radians function!
>

> Anyway, i thought i would get this off my chest and catch up with old
> friends in the meantime. We can all make Python the perfect language
> it needs to be, but it ain't gonna be easy!
> Thank you all
>
> PS stay tuned for more from this series....

Cheers,

Emm

r

unread,
Jul 30, 2009, 5:44:34 PM7/30/09
to
On Jul 30, 4:29 pm, Emmanuel Surleau <emmanuel.surl...@gmail.com>
wrote:

> > 1.) No need to use "()" to call a function with no arguments.
> > Python --> "obj.m2().m3()" --ugly
> >   Ruby --> "obj.m1.m2.m3"  -- sweeet!
> > Man, i must admit i really like this, and your code will look so much
> > cleaner.
>
> It has benefits - code does look better. It has also significant cons - it is
> ambiguous.
> For instance:
>
> a = b
>
> Is b a variable or a method called without parameter?

Hello Emanuel,
Again, who so ever names a method with such a non-descriptive name
will get whats coming to him. And if you did for some reason use such
a cryptic name as "b", do yourself (and everyone else) a favor and
follow it with "()" to denote the method call. Remember when something
is optional that means you have an option to use it OR not use it.

optional (http://definr.com/optional)
adj: possible but not necessary; left to personal choice [ant:
obligatory]


simple solutions for simple problems.

Jan Kaliszewski

unread,
Jul 30, 2009, 5:52:45 PM7/30/09
to Masklinn, pytho...@python.org
Dnia 30-07-2009 o 22:41:57 Masklinn <mask...@masklinn.net> napisał(a):

> On 30 Jul 2009, at 22:23 , Jan Kaliszewski wrote:
>> 30-07-2009 o 13:36:49 Masklinn <mask...@masklinn.net> wrote:
>>
>>> On 30 Jul 2009, at 06:04 , alex23 wrote:
>>>> On Jul 30, 1:06 pm, r <rt8...@gmail.com> wrote:

>>>>> 2.) the .each method
>>>>> container.each{|localVar| block}
>>>>> This method can really cleanup some ugly for loops, although i really
>>>>> like the readability of for loops.
>>>>

>>>> map(lambda localVar: <block>, sequence)
>>>>
>>>> or:
>>>>
>>>> def usefully_named_func(var):
>>>> <block>
>>>> return var
>>>>
>>>> transformed = [usefully_named_func(v) for v in sequence]
>>>>
>>> The issue here is of course that `map` and comprehensions are
>>> transformations. `#each` exists for effectful iterations (Ruby has
>>> `#map` for the map operation). So the intent expressed by `#each` and
>>> `map` isn't the same. Furthermore and this is the most problematic
>>> limitation of Python here, `lambda` doesn't allow complex
>>> transformations due to its restrictions, so one has to switch to named
>>> functions which works but isn't sexy (and tends to lower readability
>>> imo).
>>
>> I don't see any real limitation. What's wrong in:
>>
>> for localVar in container:
>> block
>>
> Well what's wrong with using that rather than `map`, `filter` or a list
> comprehension? (and if you don't see what the limitations of `lambda`
> are, you probably very rarely use it)

I know well about the expression-only-limitation of lambda, fortnately
there is the 'for' loop construct (or, alternatively, you can define
a named function).

And then, what's wrong with using 'for' rather than 'map', 'filter' etc.?
Agree, that 'anonymous block syntax' would be nice in some cases, but
I don't see any real limitation caused by lack of it i.e. something you
can't (all you can only with unreasonable effort).

>> And ruby's container.each is very similar to Python's iter()

> Uh… not at all…

OK, .each is like Python's iter() + some form of iterating over it
('for' loop or '[i]map'...).

Still, in this matter there is no real functionality in Ruby that you
can't reach in Python.

All that confessions of a (former?) Python fanboy are about sintactic
sugars, which importance is incomparable which such issues as e.g.
particular mechanism of classes, their inheritance etc. or even such
small helpers like function annotations.

Cheers,

Luis Zarrabeitia

unread,
Jul 30, 2009, 5:57:48 PM7/30/09
to pytho...@python.org
On Thursday 30 July 2009 04:41:57 pm Masklinn wrote:
> On 30 Jul 2009, at 22:23 , Jan Kaliszewski wrote:
> > 30-07-2009 o 13:36:49 Masklinn <mask...@masklinn.net> wrote:
> >
> > I don't see any real limitation. What's wrong in:
> >
> > for localVar in container:
> > block
>
> Well what's wrong with using that rather than `map`, `filter` or a
> list comprehension?

As I understood the question, it was "was wrong in 'for var in container' in
comparison with ruby's container.each?"

What's the (semantic) difference between

for localVar in container:
block

and

container.each{|localVar| block}

?

(the sintactic difference is quite clear... if there is no semantic
difference, I'd rather use the first version!)

Map, filter and comprehensions have little to do with that (syntactic sugar
that may allow some optimizations, but that could otherwise be replaced by
the for loop).

> (and if you don't see what the limitations of
> `lambda` are, you probably very rarely use it)

I'm not the poster, but:
* I use lambdas, a lot.
* I "know" python lambdas are limited, compared with theoretical lambdas.
* I don't [usually] see that as a "limitation".

Most of the time, the limitation is the lack of multiline/multiexpression
lambdas. But I've never seen a case where I would /prefer/ to have a
multiline function definition inside a comprehension or method invocation,
instead of a named function defined two lines before it.

(The second famous limitation is the inability to use statements inside
lambdas... luckily, now that we have a ternary operator and a print function,
it is less limiting)

> > And ruby's container.each is very similar to Python's iter()
>
> Uh… not at all…

I agree with this. It should have said that they are equivalent in the sense
that they represent the iterator protocols of both languages, and nothing
more.

I'd like to ask, what "container.each" is, exactly? It looks like a function
call (as I've learned a few posts ago), but, what are its arguments? How the
looping "works"? Does it receive a "code" object that it has to execute?
Is .each some kind of magic keyword? (This has little to do with python or
the current thread, so feel free to reply off-list if you want to...)

Regards,

Luis.

--
Luis Zarrabeitia (aka Kyrie)
Fac. de Matemática y Computación, UH.
http://profesores.matcom.uh.cu/~kyrie

r

unread,
Jul 30, 2009, 6:13:41 PM7/30/09
to
On Jul 30, 4:57 pm, Luis Zarrabeitia <ky...@uh.cu> wrote:
[snip]

> I'd like to ask, what "container.each" is, exactly? It looks like a function
> call (as I've learned a few posts ago), but, what are its arguments? How the
> looping "works"? Does it receive a "code" object that it has to execute?
> Is .each some kind of magic keyword? (This has little to do with python or
> the current thread, so feel free to reply off-list if you want to...)
>
> Regards,
>
> Luis.

Hello Luis,

I think your question is completely valid within the context of this
thread. The purpose of his thread was to get feedback on how Python
and Ruby ideas could be cumulated into the best high level language.
And being that i am the BDFL of the "Confessions of a Python Fanboy"
thread, you have my personal permission to continue on with this
subject matter...,

Robert Kern

unread,
Jul 30, 2009, 7:06:31 PM7/30/09
to pytho...@python.org
On 2009-07-30 16:44, r wrote:
> On Jul 30, 4:29 pm, Emmanuel Surleau<emmanuel.surl...@gmail.com>
> wrote:
>>> 1.) No need to use "()" to call a function with no arguments.
>>> Python --> "obj.m2().m3()" --ugly
>>> Ruby --> "obj.m1.m2.m3" -- sweeet!
>>> Man, i must admit i really like this, and your code will look so much
>>> cleaner.
>> It has benefits - code does look better. It has also significant cons - it is
>> ambiguous.
>> For instance:
>>
>> a = b
>>
>> Is b a variable or a method called without parameter?
>
> Hello Emanuel,
> Again, who so ever names a method with such a non-descriptive name
> will get whats coming to him. And if you did for some reason use such
> a cryptic name as "b", do yourself (and everyone else) a favor and
> follow it with "()" to denote the method call. Remember when something
> is optional that means you have an option to use it OR not use it.

I believe his point is that it is ambiguous to the compiler, not humans reading
the code. Python functions and methods are first class objects. They can be
passed around. If they were auto-called, then you could not do this.

--
Robert Kern

"I have come to believe that the whole world is an enigma, a harmless enigma
that is made terrible by our own mad attempt to interpret it as though it had
an underlying truth."
-- Umberto Eco

Tim Rowe

unread,
Jul 30, 2009, 8:05:29 PM7/30/09
to pytho...@python.org
2009/7/30 superpollo <us...@example.net>:
> Tim Rowe wrote:

>> Any language that gets any sort of real use has to have. For instance,
>> I love Ada's numeric types (you can specify either the minimum number
>> of significant figures or the maximum delta for a real type, and it
>> will give you a type that satisfies that -- or a compilation error if
>> it can't.  That matches genuine problem domains far better
>
> doesn't the decimal module do some of that too?

Not as far as I can tell, no.

--
Tim Rowe

Terry Reedy

unread,
Jul 30, 2009, 8:38:15 PM7/30/09
to pytho...@python.org

Nor did what I posted say that you did. The above says that superpollo
wrote "how to reverse..., as he did. Quotes are indented once more than
the author. The above says 'r wrote' with no indent and then "No...",
which you did write, indented once.

I agree that since I did not quote anything that you wrote, I should
also have snipped your name. But I least I do attempt to snip material
irrelavant to my comments.

Terry Jan Reedy

I V

unread,
Jul 31, 2009, 1:27:22 AM7/31/09
to
On Thu, 30 Jul 2009 17:57:48 -0400, Luis Zarrabeitia wrote:
> As I understood the question, it was "was wrong in 'for var in
> container' in comparison with ruby's container.each?"
>
> What's the (semantic) difference between
>
> for localVar in container:
> block
>
> and
>
> container.each{|localVar| block}

I don't think "each" is a particularly compelling example of Ruby's
blocks - as you say, it's easily replaceable with a Python for-loop. The
advantage of Ruby's syntax is that it allows you to define further
functions that are sort-of like new control structures. So you have
things like:

File.open('myfile', 'r') do |file|
while line = file.gets
puts line
end
end

Which is like a python's:

with open('myfile', 'r) as f:
for line in f:
print f

However, with Ruby, this kind of scoping construct can be added without
adding new syntax. Another interesting example is the Sinatra web
framework, which allows you to write a web app with something like:

get '/' do
"Index page"
end

post '/:name' do
"Posted to " + params[:name]
end

Which looks something like a DSL for web apps, but is accomplished solely
with normal ruby functions. More: http://www.sinatrarb.com/intro.html

Ruby blocks are, fundamentally, syntactic sugar, but they are kind of
neat.

Emmanuel Surleau

unread,
Jul 31, 2009, 1:46:49 AM7/31/09
to pytho...@python.org
On Friday 31 July 2009 01:06:31 Robert Kern wrote:
> On 2009-07-30 16:44, r wrote:
> > On Jul 30, 4:29 pm, Emmanuel Surleau<emmanuel.surl...@gmail.com>
> >
> > wrote:
> >>> 1.) No need to use "()" to call a function with no arguments.
> >>> Python --> "obj.m2().m3()" --ugly
> >>> Ruby --> "obj.m1.m2.m3" -- sweeet!
> >>> Man, i must admit i really like this, and your code will look so much
> >>> cleaner.
> >>
> >> It has benefits - code does look better. It has also significant cons -
> >> it is ambiguous.
> >> For instance:
> >>
> >> a = b
> >>
> >> Is b a variable or a method called without parameter?
> >
> > Hello Emanuel,
> > Again, who so ever names a method with such a non-descriptive name
> > will get whats coming to him. And if you did for some reason use such
> > a cryptic name as "b", do yourself (and everyone else) a favor and
> > follow it with "()" to denote the method call. Remember when something
> > is optional that means you have an option to use it OR not use it.
>
> I believe his point is that it is ambiguous to the compiler, not humans
> reading the code.

Actually, both. Use a variable you didn't initialize? This is what you get:

NameError: undefined local variable or method `b' for main:Object
from (irb):1

The compiler has no idea if b is a variable or a method. It also makes it very
easy to shadow an existing method by declaring a variable of the same name,
which is problematic. I suppose it is a side-effect of Ruby's Perl
philosophical inheritance - except that Perl uses sigils to prefix its
variables, negating this issue.

Cheers,

Emm

Steven D'Aprano

unread,
Jul 31, 2009, 3:28:29 AM7/31/09
to
On Thu, 30 Jul 2009 18:06:31 -0500, Robert Kern wrote:

> On 2009-07-30 16:44, r wrote:
>> On Jul 30, 4:29 pm, Emmanuel Surleau<emmanuel.surl...@gmail.com> wrote:
>>>> 1.) No need to use "()" to call a function with no arguments. Python
>>>> --> "obj.m2().m3()" --ugly
>>>> Ruby --> "obj.m1.m2.m3" -- sweeet!
>>>> Man, i must admit i really like this, and your code will look so much
>>>> cleaner.
>>> It has benefits - code does look better. It has also significant cons
>>> - it is ambiguous.
>>> For instance:
>>>
>>> a = b
>>>
>>> Is b a variable or a method called without parameter?
>>
>> Hello Emanuel,
>> Again, who so ever names a method with such a non-descriptive name will
>> get whats coming to him. And if you did for some reason use such a
>> cryptic name as "b", do yourself (and everyone else) a favor and follow
>> it with "()" to denote the method call. Remember when something is
>> optional that means you have an option to use it OR not use it.
>
> I believe his point is that it is ambiguous to the compiler, not humans
> reading the code. Python functions and methods are first class objects.
> They can be passed around. If they were auto-called, then you could not
> do this.

Oh my, "r" is still around is he??? And now he's singing the praises of
Ruby, the language which he treated as the Devil's Spawn when he first
arrived. That's hilarious.

But back on topic... "r" has missed the point. It's not that a=b is hard
to understand because b is a poor name. The example could have been:

def factory_function():
magic = time.time() # or whatever
def inner():
return magic
return inner

my_function = factory_function

It's still ambiguous. Does the programmer intend my_function to become
factory_function itself, or the output of factory_function?

In Python, it's not ambiguous at all -- my_function is set to
factory_function, and *not* the output of factory_function, because you
haven't called the function.

Python's model is consistent and simple: given a function "func", you
*always* refer to the function object itself as func and you *always*
call it with func(). This applies no matter how many arguments the
function takes, or what it returns, or where it is defined.

I think it's telling that "r" the fanboy has rejected Python's advantages
(simplicity, consistency, unambiguity) in favour of lazily saving two
keystrokes.

--
Steven

Masklinn

unread,
Jul 31, 2009, 3:48:24 AM7/31/09
to pytho...@python.org
On 30 Jul 2009, at 23:52 , Jan Kaliszewski wrote:
> Dnia 30-07-2009 o 22:41:57 Masklinn <mask...@masklinn.net>
> napisał(a):
> On 30 Jul 2009, at 22:23 , Jan Kaliszewski wrote:
>>> 30-07-2009 o 13:36:49 Masklinn <mask...@masklinn.net> wrote:
>>>> On 30 Jul 2009, at 06:04 , alex23 wrote:
>>>>> On Jul 30, 1:06 pm, r <rt8...@gmail.com> wrote:
>>>>>> 2.) the .each method
>>>>>> container.each{|localVar| block}
>>>>>> This method can really cleanup some ugly for loops, although i
>>>>>> really
>>>>>> like the readability of for loops.
>>>>>
>>>>> map(lambda localVar: <block>, sequence)
>>>>>
>>>>> or:
>>>>>
>>>>> def usefully_named_func(var):
>>>>> <block>
>>>>> return var
>>>>>
>>>>> transformed = [usefully_named_func(v) for v in sequence]
>>>>>
>>>> The issue here is of course that `map` and comprehensions are
>>>> transformations. `#each` exists for effectful iterations (Ruby
>>>> has `#map` for the map operation). So the intent expressed by
>>>> `#each` and `map` isn't the same. Furthermore and this is the
>>>> most problematic limitation of Python here, `lambda` doesn't
>>>> allow complex transformations due to its restrictions, so one has
>>>> to switch to named functions which works but isn't sexy (and
>>>> tends to lower readability imo).
>>>
>>> I don't see any real limitation. What's wrong in:
>>>
>>> for localVar in container:
>>> block
>>>
>> Well what's wrong with using that rather than `map`, `filter` or a
>> list comprehension? (and if you don't see what the limitations of
>> `lambda` are, you probably very rarely use it)
>
> I know well about the expression-only-limitation of lambda, fortnately
> there is the 'for' loop construct (or, alternatively, you can define
> a named function).
>
> And then, what's wrong with using 'for' rather than 'map', 'filter'
> etc.?
Nothing, but then again nothing's wrong using C's for either.

But I do think that using higher-order functions:
* tends to be terser while not going overly terse, it only removes
boilerplate
* is more composable (it's pretty easy to tack another transformer in
your chain, the same way defining iterator/generator transformers and
chaining them is simpler than doing the same thing using explicit
`for…in`)
* it clearly spells the intent of the programmer, while `for` can be
anything and everything, and one has to dive into the code to know
even the high-level operations performed (is it a basic
transformation? A filtering or partitioning? A reduction? An
application of side effects?)


> Agree, that 'anonymous block syntax' would be nice in some cases, but
> I don't see any real limitation caused by lack of it i.e. something
> you
> can't (all you can only with unreasonable effort).
>

There are no limitations, but once again there never are. There are no
actual limitations to using conditional jumps over iterators either.

>>> And ruby's container.each is very similar to Python's iter()
>
>> Uh… not at all…
>

> OK, .each is like Python's iter() + some form of iterating over it
> ('for' loop or '[i]map'...).

Well of course Enumerable#each is similar to map/imap, it's the same
core principle.

Masklinn

unread,
Jul 31, 2009, 4:08:33 AM7/31/09
to pytho...@python.org
On 30 Jul 2009, at 23:57 , Luis Zarrabeitia wrote:
> I'd like to ask, what "container.each" is, exactly? It looks like a
> function
> call (as I've learned a few posts ago), but, what are its arguments?
> How the
> looping "works"? Does it receive a "code" object that it has to
> execute?
> Is .each some kind of magic keyword? (This has little to do with
> python or
> the current thread, so feel free to reply off-list if you want to...)

#each is simply a method that takes a function (called blocks in
ruby). One could call it a higher-order method I guess.

It's an implementation of the concept of internal iteration: instead
of collections yielding iterator objects, and programmers using those
through specially-built iteration constructs (e.g. `for…in`),
collections control iteration over themselves (the iteration is
performed "inside" the collection, thus the "internal" part) and the
programmer provides the operations to perform at each iterative step
through (usually) a function.

In Python (assuming we had anonymous defs and an each method on
lists), the following loop:

for item in some_list:
do_something(item)
do_something_else(item)

some_list.each((def (item):
do_something(item)
do_something_else(item)
))

There's absolutely nothing magic there, it's simply using anonymous
functions and method calls (SmallTalk initiated this approach in the
70s, and actually went much, much further than Ruby as it did away not
only with `for…in` but also with `if…else` and `while` and a bunch of
other stuff).

Now as IV pointed out, #each isn't the most interesting usage of
blocks/anonymous functions (though I do like it, because it gets rid
of no less than two keywords… even if Ruby reintroduced them as
syntactic sugar), higher-order functions (functions which act on other
functions) are (among other things) ways to create new control
structures without having to extend the core language (so are lisp-
style macros, by the way).

Of course Python does have higher-order functions (functions are first-
class objects, so it's possible and frequent to have functions act on
other functions), but since Python doesn't have anonymous functions
that usage tends to be a bit too verbose beyond simple cases (also, of
course, this kind of usages is neither in the "genes" nor in the
stdlib).

In closing, IV has an example of how blocks make `with` unnecessary in
Ruby (the functionality can be implemented at the library level rather
than the language one). Generally, anonymous functions in OO languages
are a way to inject behavior into third-party methods/objects. Kind-of
a first-class Visitor support.

-m

PS: there's actually a bit of syntactic magic in Ruby's blocks, and
it's one of the things I hate in the language, but it's not relevant
to the role of blocks, and unnecessary to it: SmallTalk has no magical
syntax).

Steven D'Aprano

unread,
Jul 31, 2009, 4:13:50 AM7/31/09
to
On Thu, 30 Jul 2009 18:47:04 +0100, Tim Rowe wrote:

> That and the fact that I couldn't stop laughing for long enough to learn
> any more when I read in the Pragmatic Programmer's Guide that "Ruby,
> unlike less flexible languages, lets you alter the value of a constant."
> Yep, as they say "Bug" = "Undocumented feature"!

That's no different from Python's "constant by convention". We don't even
get a compiler warning!

On the other hand, we don't have to prefix names with @ and @@, and we
don't have the compiler trying to *guess* whether we're calling a
function or referring to a variable.

Somebody who knows more Ruby than me should try writing the Zen of Ruby.
Something like:

Line noise is beautiful.
Simplicity is for the simple.
Complicated just proves we're smart.
Readability only matters to the schmuck who has to maintain our code.
Special cases require breaking the rules.
In the face of ambiguity, try to guess. Go on, what could go wrong?
The more ways to do it, the better.

Although I'm sure Ruby has its good points. I'm not convinced anonymous
code blocks are one of them though.


--
Steven

Chris Rebert

unread,
Jul 31, 2009, 4:25:37 AM7/31/09
to Xavier Ho, pytho...@python.org
On Fri, Jul 31, 2009 at 1:21 AM, Xavier Ho<con...@xavierho.com> wrote:
> On Fri, Jul 31, 2009 at 6:08 PM, Masklinn <mask...@masklinn.net> wrote:
>>
>> <snip>... but since Python doesn't have anonymous functions that usage
>> tends to be a bit too verbose ... <snip>
>
> Sorry to interrupt, but wouldn't lambda in Python be considered as
> 'anonymous functions'?

I believe "full" anonymous functions was intended by the author.
lambdas are limited to a single expression. "Full" anonymous functions
would be allowed to contain multiple statements.

Cheers,
Chris
--
http://blog.rebertia.com

Chris Rebert

unread,
Jul 31, 2009, 4:38:16 AM7/31/09
to Xavier Ho, pytho...@python.org
On Fri, Jul 31, 2009 at 1:31 AM, Xavier Ho<con...@xavierho.com> wrote:

> On Fri, Jul 31, 2009 at 6:25 PM, Chris Rebert <cl...@rebertia.com> wrote:
>>
>> I believe "full" anonymous functions was intended by the author.
>> lambdas are limited to a single expression. "Full" anonymous functions
>> would be allowed to contain multiple statements.
>>
> Cheers, but what about this:
>
>  def goBig(x):
>     while True:
>         x = x ** 2
>         yield x
>
> for result in goBig(10):
>     if result > 10 ** 100:
>         break
>     print result
>
> It's a silly example, but wouldn't goBig(10) in this example be a "full
> anonymous function"?

No, because it has a name, namely "goBig"; this obviously prevents it
from being "anonymous".

For comparison, note how the function in the following example is
never given a name, and is thus anonymous:
>>> (lambda x: x+5)(6)
11

Jean-Michel Pichavant

unread,
Jul 31, 2009, 5:20:47 AM7/31/09
to r, pytho...@python.org
r wrote:
> The purpose of his thread was to get feedback on how Python
> and Ruby ideas could be cumulated into the best high level language.
> And being that i am the BDFL of the "Confessions of a Python Fanboy"
> thread, you have my personal permission to continue on with this
> subject matter...,
>
>
Challenging even the most accepted mechanisms of a language is a proof
of intelligence.

Descartes's doubt method :
"The basic strategy of /Descartes/
<http://www.philosophypages.com/ph/desc.htm>'s method of doubt
<http://www.philosophypages.com/dy/d9.htm#doubt> is to defeat skepticism
<http://www.philosophypages.com/dy/s5.htm#skep> on its own ground. Begin
by doubting the truth of everything�not only the evidence
<http://www.philosophypages.com/dy/e9.htm#evid> of the senses and the
more extravagant cultural presuppositions, but even the fundamental
process of reasoning itself. If any particular truth about the world can
survive this extreme skeptical challenge, then it must be truly
indubitable and therefore a perfectly certain foundation for knowledge"

So let's make the method call parenthesis a "truly indubitable and
therefore a perfectly certain foundation".

Those who want to remove the parenthesis on python method calls raise
the hand !

JM

Masklinn

unread,
Jul 31, 2009, 5:49:31 AM7/31/09
to Chris Rebert, pytho...@python.org
On 31 Jul 2009, at 10:25 , Chris Rebert wrote:

> On Fri, Jul 31, 2009 at 1:21 AM, Xavier Ho<con...@xavierho.com>
> wrote:
>> On Fri, Jul 31, 2009 at 6:08 PM, Masklinn <mask...@masklinn.net>
>> wrote:
>>>
>>> <snip>... but since Python doesn't have anonymous functions that
>>> usage
>>> tends to be a bit too verbose ... <snip>
>>
>> Sorry to interrupt, but wouldn't lambda in Python be considered as
>> 'anonymous functions'?
>
> I believe "full" anonymous functions was intended by the author.
> lambdas are limited to a single expression.
Yes, and they're limited to a single *expression*, so before Python 3,
lambda: print "foo" is out. Likewise, it isn't possible to have an if/
else statement within a lambda (though a ternary is ok), or a with, …
since Python statements aren't expressions.

Iain King

unread,
Jul 31, 2009, 5:54:50 AM7/31/09
to
On Jul 31, 8:28 am, Steven D'Aprano <st...@REMOVE-THIS-

Not only that - does 'return inner' return the function inner or the
result of function inner?

How does ruby pass a function as an object?

Iain

Masklinn

unread,
Jul 31, 2009, 6:32:56 AM7/31/09
to pytho...@python.org
Ruby doesn't have functions as such. It has methods and blocks (which
would be anonymous functions). `def` always creates methods.

To get a (bound) method object, you simply call `method` on an
instance e.g. `foo.method(:bar)` is equivalent to `foo.bar` in Python
(it returns a bound method object without calling it).

Blocks are usually created as part of the calls: `foo.bar
{do_something}` the part between braces (braces included) is a block,
which will be passed to the method `bar`. Sadly, Ruby's blocks are
magical syntax (doesn't mean they have to be, in Smalltalk there's
nothing magical about blocks for instance) so you can't just do `foo =
{do_something}`, you have to turn them into `Proc` objects with the
`proc` constructor (or `lambda`, it's equivalent and looks better so
I'll use that): `foo = lambda {do_something}`. If you use the magical
syntax previously shown, Ruby handles the turning of a block into an
actual `Proc` instance.

And since Ruby doesn't have a `()` operator, it uses a method instead
(`#call`), so you simply do `foo.call` to execute the proc and get its
value.

All in all, much like Smalltalk, Ruby tends not to favor raw functions
the way Python does, so a direct translation of the Python code
doesn't make much sense.

Bruno Desthuilliers

unread,
Jul 31, 2009, 7:38:56 AM7/31/09
to
Steven D'Aprano a écrit :

> On Thu, 30 Jul 2009 18:47:04 +0100, Tim Rowe wrote:
>
>> That and the fact that I couldn't stop laughing for long enough to learn
>> any more when I read in the Pragmatic Programmer's Guide that "Ruby,
>> unlike less flexible languages, lets you alter the value of a constant."
>> Yep, as they say "Bug" = "Undocumented feature"!
>
> That's no different from Python's "constant by convention".

Well, at least Python doesn't pretend to have real symbolic constants -
we all know it's only a convention !-)

> We don't even
> get a compiler warning!

Of course - from the compiler's POV, it's only usual rebinding.

> On the other hand, we don't have to prefix names with @ and @@,

Nope, we have to prefix them with 'self' or 'cls' (or even
'self.__class__').

> and we
> don't have the compiler trying to *guess* whether we're calling a
> function or referring to a variable.

Please re-read a bit more carefully - it's *all* method call. Python is
'uniform' in obj.name is always an attribute lookup (methods being
attributes), Ruby is uniform in that 'obj.name' is always a method call.

> Somebody who knows more Ruby than me should try writing the Zen of Ruby.
> Something like:

(snip childish parody of Python Zen)

Steven, is that any useful ?

>
> Although I'm sure Ruby has its good points. I'm not convinced anonymous
> code blocks are one of them though.

Ruby's code blocks come from Smalltalk, where they are an absolute
necessity since message passing (which code blocks are part of) is the
*only* builtin control flow in Smalltalk - so you just *need* this
construction to provide branching and iterations.

Wether it makes sense to have code blocks in Ruby is another question
since Ruby does provide traditional control flow features, but then one
could question Python's "lambda" (hem...) too.

Masklinn

unread,
Jul 31, 2009, 8:18:56 AM7/31/09
to pytho...@python.org
On 31 Jul 2009, at 13:38 , Bruno Desthuilliers wrote:
> Steven D'Aprano a écrit :
>> On Thu, 30 Jul 2009 18:47:04 +0100, Tim Rowe wrote:
>>> That and the fact that I couldn't stop laughing for long enough to
>>> learn
>>> any more when I read in the Pragmatic Programmer's Guide that "Ruby,
>>> unlike less flexible languages, lets you alter the value of a
>>> constant."
>>> Yep, as they say "Bug" = "Undocumented feature"!
>> That's no different from Python's "constant by convention".
> Ruby's code blocks come from Smalltalk, where they are an absolute
> necessity since message passing (which code blocks are part of) is
> the *only* builtin control flow in Smalltalk - so you just *need*
> this construction to provide branching and iterations.
>
I'm not so sure about the way you say it. I'm pretty sure
"traditional" flow control structures preceded Smalltalk by a pair of
decades so it's not that Smalltalk's designers found it necessary to
use blocks & messages, but that they understood blocks & messages
could trivially replace most control structures (making *those*
unnecessary), making the core language simpler and more flexible.

In other words, I see it the other way around.

> Wether it makes sense to have code blocks in Ruby is another
> question since Ruby does provide traditional control flow features

Well it does at least allow for the creation of new flow control
structures in library land when the existing ones aren't enough (e.g.
allows Ruby not to require the introduction of a `with` statement).
Though Ruby's blocks are nowhere near as flexible as Smalltalk's.

Bruno Desthuilliers

unread,
Jul 31, 2009, 9:12:42 AM7/31/09
to
Masklinn a �crit :

> On 31 Jul 2009, at 13:38 , Bruno Desthuilliers wrote:
>> Steven D'Aprano a �crit :

>>> On Thu, 30 Jul 2009 18:47:04 +0100, Tim Rowe wrote:
>>>> That and the fact that I couldn't stop laughing for long enough to
>>>> learn
>>>> any more when I read in the Pragmatic Programmer's Guide that "Ruby,
>>>> unlike less flexible languages, lets you alter the value of a
>>>> constant."
>>>> Yep, as they say "Bug" = "Undocumented feature"!
>>> That's no different from Python's "constant by convention".
>> Ruby's code blocks come from Smalltalk, where they are an absolute
>> necessity since message passing (which code blocks are part of) is the
>> *only* builtin control flow in Smalltalk - so you just *need* this
>> construction to provide branching and iterations.
>>
> I'm not so sure about the way you say it.

I'm not sure about the way you understand it !-)

> I'm pretty sure "traditional"
> flow control structures preceded Smalltalk by a pair of decades

Yes, of course - and that's not the point. What's important is that:


> so it's
> not that Smalltalk's designers found it necessary to use blocks &
> messages, but that they understood blocks & messages could trivially
> replace most control structures (making *those* unnecessary), making the
> core language simpler and more flexible.

Exactly.

> In other words, I see it the other way around.

My wording may have been a bit confusing, indeed. It was implied (but
perhaps a bit unclear) that restricting control structures to messages
and blocks was a design choice.

>> Wether it makes sense to have code blocks in Ruby is another question
>> since Ruby does provide traditional control flow features
>
> Well it does at least allow for the creation of new flow control
> structures in library land when the existing ones aren't enough (e.g.
> allows Ruby not to require the introduction of a `with` statement).

Yeps. But then other "traditionnal" control flow features become redundant.

Masklinn

unread,
Jul 31, 2009, 9:39:47 AM7/31/09
to pytho...@python.org
On 31 Jul 2009, at 15:12 , Bruno Desthuilliers wrote:
> Masklinn a écrit :

>> On 31 Jul 2009, at 13:38 , Bruno Desthuilliers wrote:
>>> Steven D'Aprano a écrit :

>>>> On Thu, 30 Jul 2009 18:47:04 +0100, Tim Rowe wrote:
>>>>> That and the fact that I couldn't stop laughing for long enough
>>>>> to learn
>>>>> any more when I read in the Pragmatic Programmer's Guide that
>>>>> "Ruby,
>>>>> unlike less flexible languages, lets you alter the value of a
>>>>> constant."
>>>>> Yep, as they say "Bug" = "Undocumented feature"!
>>>> That's no different from Python's "constant by convention".
>>> Ruby's code blocks come from Smalltalk, where they are an absolute
>>> necessity since message passing (which code blocks are part of) is
>>> the *only* builtin control flow in Smalltalk - so you just *need*
>>> this construction to provide branching and iterations.
>
[misunderstandings on my part/clarifications on yours]

>> Well it does at least allow for the creation of new flow control
>> structures in library land when the existing ones aren't enough
>> (e.g. allows Ruby not to require the introduction of a `with`
>> statement).
>
> Yeps. But then other "traditionnal" control flow features become
> redundant.
They can be anyway: Ruby doesn't deprecate most control flows as the
actual usages of blocks are a bit restricted (cannot be used for
`while` as it would require the serialization to a Proc, and Ruby's
syntax doesn't allow sending multiple blocks to a method so `if…else`
is out as well). And I assume they reintroduced the for…in sugar to
ease the transition from more traditional languages (using #each and
others seems the suggested collection iterators across the community).

Ethan Furman

unread,
Jul 31, 2009, 11:08:29 AM7/31/09