
What Pythonistas Think of Ruby - sant0sk1
http://blog.peepcode.com/tutorials/2010/what-pythonistas-think-of-ruby
======
old-gregg
As someone who did nothing but Rails since 06 (two Rails-powered startups,
plus some Rails contracting), allow me to explain why I dumped Ruby/Rails and
switched to Python/Pylons.

Batteries. Ruby is great, but outside of Rails you are on your own. Even basic
things like geometry needs to be coded by hand. Python (and almost anything
else) simply destroys Ruby when it comes to generic non-web centric libraries.
And the situation isn't changing: most new Ruby "libraries" are just add-ons
to Rails, seriously, how many Rails unit testing frameworks, paginators and
file upload handlers do we need?

People. Python hackers are much, much nicer folks to hang around with. I don't
like to start a war here so I'll refrain from going further with this point.
Besides, I feel like Zed Shaw said it all.

~~~
sreque
Do you really have to switch from one to another? I learned both languages,
love them both, and use them both. There's too much hate in the world of
programming languages.

~~~
patio11
The fights are so vicious because the stakes are so small. (Originally said
about academics, but works for programmers, too.)

~~~
berntb
I have the definitive impression that the Pythonistas are more interested in
this fighting than most other language cultures.

I might be wrong, but I really can't mention any other group of people
trolling Perl discussions. It is the same for Ruby?

It really seems strange for a language which got the name from Monthy Python.
(-: Is it some inferiority feelings to environments which are _fun_? :-)

~~~
jrockway
_I might be wrong, but I really can't mention any other group of people
trolling Perl discussions._

 _Everyone_ is out trolling the Perl discussions. PHP developers hate us, Java
developers hate us, Ruby developers hate us, and Python developers hate us. I
think this is funny, because we generally don't hate the other languages, we
just embrace and extend their good ideas for Perl. (The Perl community has
come up with a few good ideas on their own, but the best ideas have been
borrowed from other languages. Moose is from Smalltalk and CL; PSGI is from
Python; Plack is from Ruby; Catalyst is from Java; etc. I think, in general,
the stolen ideas have been improved upon in Perl; I like using Moose a lot
more than I like using CLOS -- and I like using CLOS a lot.)

The only place outside of the Perl community where I can admit to liking Perl
(and not be flamed) is #haskell. But everyone is nice there.

(I've even been trolled in real life over my like of Perl. I was going after
some girl, who apparently had a friend that was a Java developer. Perl came
up, I came up, and it was resolved "he must not be very good at programming if
he prefers Perl over Java". Guess who got the girl? Not the Perl programmer.)

~~~
chromatic
> Moose is from Smalltalk and CL...

... and Perl 6.

~~~
jrockway
Yes, you're right. Adding state to traits is definitely a Perl 6 innovation.

------
KirinDave
> Ruby takes full advantage of the Lisp chainsaw.

I always get a little sad and slightly irritated when I hear people say things
like this. This is a statement born from ignorance and misunderstanding.

What ruby does to present micro-DSLs are what any language that lets the
programmer influence the scope of single dispatch and has a lightweight syntax
for function calls can do. They are not what Lisp macros do, and do not even
approach all the common "easy" uses cases for macros. Further, they also incur
a much larger runtime performance penalty, whereas macros incur none.

Ruby has so many merits on its own. There is no need to drum up nonsense about
how it's a "lisp without the parenthesis".

~~~
showell
You might be taking the statement out of context, and you are certainly
quoting it out of context (although brevity is appreciated.)

The statement in the talk was made to illustrate the differences between Ruby
and Python, and it was not made to suggest that Ruby was replicating all the
benefits of Lisp.

~~~
KirinDave
I understand the intent, but I do not feel that it loses its incorrectness by
taking it out of context.

That people even feel this comparison is appropriate is what has me depressed.
It represents a fairly fundamental set of misunderstandings.

~~~
chromatic
> That people even feel this comparison is appropriate is what has me
> depressed.

I agree; you can replace the term "DSL" with "API" in almost every case
without losing any essential meaning. (You have to give the hipper-than-thou
language pseudo-advocacy, but that's no loss.)

~~~
mjw
I think in those contexts, DSL is more a description of how an API _feels_ to
use, than a precise technical categorisation.`

Ergonomic distinctions are useful though, as is the distinction between
declarative-style APIs and more imperative ones, which 'DSL' is often used to
make.

~~~
kscaldef
I have yet to see a Ruby "DSL" that didn't feel like Ruby. That is,

    
    
      unless you.talk :like => "this"

~~~
kemiller
Those are just the "english-y" DSLs. Not all are attempting to read like
english. And even for those that are, the point isn't to be writing in
english, the point is to be at least halfway readable to a non-programmer
reading over your shoulder.

~~~
kscaldef
Okay, but it's not really all that clear that "sum.should == 3" is actually
any more readable than "assert(sum == 3)". (Do you really have non-programmers
reading code over your shoulder? I can't think of any case in a 10+ year
career where that's happened.)

~~~
kemiller
I don't personally use the stuff. :) But I have seen environments where that
does happen, and it works pretty well for them.

If you're not doing that, I think they're kind of silly.

------
pavelludiq
I am one of those people who accepted the lisp religion of "syntax is evil". I
have a descent knowledge of python, and I've read a few ruby tutorials.

Neither python nor ruby are lisp. Python is not cool because of generators,
list comprehensions, decorators or any other feature. Ruby is not cool because
of blocks or monkey patching(im suspicions of anything called MONKEY
patching). Ruby and python are cool because of really cool libraries and the
way people use these languages, not because they have especially well designed
syntax.

Instead of arguing about how cool your crappy syntax is, argue about which has
the better libraries, which implementation is better, which is used for cooler
projects. Non of these languages can top lisp when it comes to expressiveness
and flexibility.

~~~
wvenable
Syntax is human. Syntax is ergonomics. A programming language is the bridge
between man and machine. Lisp, I would argue, is far more about the machine
than the man and that is the simple reason why it's not more popular.

Python was cool before the libraries; that's why those libraries got written
in the first place. Lisp has been around forever and is still lacking in
libraries and other support.

~~~
pavelludiq
"Lisp, I would argue, is far more about the machine than the man and that is
the simple reason why it's not more popular."

Pleas do, i would love to hear your argument. I fail to see how lisp is less
humane than python, when i find it to be exactly the opposite.

Edit: what i meant was that lisp is more about the human, not that python is
more about the machine, i hope i don't get misunderstood.

~~~
brettnak
As a non lisp programmer, it is hard for me to automatically see what is going
on in a lisp program because of mismatched " ' " and a lot of parenthesis. I
believe this is one of his points. When I was learning python, or ruby, for
that matter ( I use both! ) I never felt like I had no idea what was going on
in the code even before I learned the languages.

~~~
silentbicycle
Should this really be so surprising, though? Lisp is based on a different
model of computation than Python and Ruby. You can't follow non-trivial C code
without understanding pointers, or Prolog without understanding unification.

Syntax aside, the semantics of Python are intended to be unsurprising to
people with a conventional programming background. I don't have any practical
experience with Ruby, but it looks like a mishmash of Smalltalk and Perl to
me, and I can usually get the gist of code snippets. Likewise, I can kinda-
sorta follow written Dutch (since I've studied German and speak English
fluently), but I wouldn't expect to be able to just read Thai.

~~~
apotheon
> I don't have any practical experience with Ruby, but it looks like a
> mishmash of Smalltalk and Perl to me

Those are, I think, probably the two most influential sources of inspiration
for how the language is put together, in terms of the actual end result.

------
jamesbritt
Wow. First a post on awesomeness of Haml, leading to the usual "Is not!", "Is
too!" discussion.

Now a post on Python v. Ruby?

It must be Shark Week on HN.

------
gsiener
Not related to the article, but I really like the setting and layout of the
top section. Felt like I was reading a magazine!

~~~
sant0sk1
These fancy new blogazines, as the kids are calling them, make me really wish
I had design chops. My regular old blog looks so lame and uninteresting by
comparison.

~~~
r11t
Raganworld's markdown rendered blog @ github
<http://github.com/raganwald/homoiconic> has convinced me that while eye-candy
and design is great, it is the content of the blog post itself that is of more
value to me as a reader.

~~~
Silhouette
Ironically, it did the opposite for me. I used to read and enjoy Reg's blog
posts. Since he made the change to the new format, I don't think I've read
anything he's written there: it doesn't work like anything else any more, and
while his blog was one of those I enjoyed, I rarely go out of my way to find
content like that when there are many other blogs competing for my limited
spare time.

------
junklight
Python versus Ruby has always struck me as one of the absurd battles ever. The
two languages seem to address a very similar space and have broadly similar
features sets.

Yes there are points of variation but both seem to work really well. People
build cool and useful stuff in both. People are productive in both.

As for me - I personally like the syntax of Python better. That could be
because I learnt it first - or it could just be something in me. Who knows?

and who cares...

~~~
dschobel
I think a big reason why it comes up so often is that it's rarely worth the
mental real-estate to become proficient in both since they are so similar in
design and problem domain.

There is significant diminished utility in learning python after knowing ruby
or vice versa. You're better of learning something totally different (like
haskell!) since you already have a flexible modern scripting language with a
great web-framework in your toolkit.

However since each language has its trade offs, people have to keep convincing
themselves (loudly and publicly, usually) that they made the right decision.

So basically, it's contentious and will always be that way for the same
reasons that people still debate vim vs emacs after twenty years.

~~~
pmiller2
This right here is the exact reason that I, as a fairly experienced and
hopefully pretty good Python programmer feel absolutely no desire to learn
Ruby. It doesn't offer me anything in terms of making me think differently
about programming than Python, and I don't see any particular domain (other
than, of course, Rails) where it offers an advantage in libraries or anything.
On the other hand, had I stumbled upon Ruby first and then found out about
Python, I'm sure I probably wouldn't feel any need to learn Python, either.

------
megamark16
My take away: As a Python developer, I should really check out Ruby. It's like
Python in some ways, but in other ways it may help give me an additional
perspective on programming.

Thanks for the article! Mark

~~~
kemiller
More replies like this one, please!

------
nfnaaron
"The Seattle Python community represented there was almost painfully polite.
... I later learned that this may be an attribute unique to Seattle Python
developers."

When I lived in Seattle, I read that musicians, playing in PNW clubs and
venues and noticing a lower audience energy level than they were used to,
sometimes had to be reassured by club owners that yes, the audience really
does like you, really, it's just that PNW audiences are more subdued, laid
back and polite.

------
lsb
It's not self.call(:my_method) --- that's nuts. It's my_method[param1, param2]
which is aliased to my_method.call(param1, param2). Ruby's syntax can be a
crapfest (like Procs not being callable without [] instead of () for example),
but this isn't an example.

~~~
tptacek
proc[arg1,arg2] is terrible; strictly worse than proc.call arg1, arg2. When I
see an id followed by brackets, I'm looking at a collection, not a callable.
This is only exacerbated by Ruby's weird/useful [index,length] convention.

~~~
lsb
I think what we both want is proc(arg1, arg2).

~~~
duairc
In newer versions of Ruby you can do proc.(arg1, arg2), which I think is a
decent compromise.

------
DanielStraight
I think this is a good explanation of some of the very real differences
between Python and Ruby. The lambda issue is almost enough to get me back to
Ruby after switching to Python. I stick with Python mostly because of syntax
(especially significant whitespace) and the batteries-included philosophy. I'm
also in love with a Python library called pyparsing, the equivalent of which I
haven't seen in any other language.

~~~
mclin
I'm not sure I get the lambda issue. If you want a > 1 line lambda why not
just define a function?

    
    
        def a(x):
            def b():
               print x
            return b
    

Not sure what a prototypical ruby usecase would be.

~~~
gcampbell
The other side of the argument: why support anonymous functions, but restrict
them to one line? That seems highly arbitrary.

~~~
fuzzyman
Nope - not arbitrary, it is because of the indentation scoping rules. Try
coming up with a syntax for statement based lambdas that isn't ugly as heck.

~~~
jashkenas
First, links for context.

Guido's take: <http://www.artima.com/weblogs/viewpost.jsp?thread=147358>

Arcieri's take: [http://www.unlimitednovelty.com/2009/03/indentation-
sensitiv...](http://www.unlimitednovelty.com/2009/03/indentation-sensitivity-
post-mortem.html)

It's not hard if we disallow statements, and make everything into an
expression that returns a value -- something that Ruby does right. The value
of a block of statements is just the value of the last statement in the block.

So, whether you call it a function, or a method, or a lambda, or a block,
whitespace with multi-line expressions can be made to work.

The commonly-cited lambda-with-multiple-prints example, in CoffeeScript:

    
    
        count: ->
          print 'one'
          print 'two'
          print 'three'

------
PostOnce
That's not a python, that's a milk snake. Feel free to downvote me for
pointing that out.

------
rbanffy
"Without powerful blocks and lambdas, you can’t have Rake. You can’t have
RSpec. You can’t have Sinatra’s clear REST syntax."

Can anyone explain why?

~~~
mcav
Disagree on "REST syntax". Python could do just as well:

Sinatra:

    
    
      get '/hi' do
        "Hello World!"
      end
    

Python 2:

    
    
      @get('/hi')
      def hello():
        return "Hello World"
    

Python 3:

    
    
      def hello() -> "/hi":
        return "Hello World"

~~~
steveklabnik
A Rubyist would argue that that Python 2 syntax is anything but clear.

I have no idea what that Python 3 snippet is doing... care to share? That
looks like something that's hard to Google...

~~~
fuzzyman
As a Pythonista I have no idea what the Ruby snippet is doing. Readability
depends entirely on context.

The Python 3 version is using a function annotation.

In Python 2 or 3 you could use a context manager (with statement) to similar
effect.

~~~
aerique
_As a Pythonista I have no idea what the Ruby snippet is doing. Readability
depends entirely on context._

Oh, come on. You're just disagreeing for effect here.

I've never used Ruby but that snippet is clear as day.

The Python 3 snippet suggests to me that the output would be "/hi" though :)

~~~
Confusion

      Oh, come on. You're just disagreeing for effect here.
      I've never used Ruby but that snippet is clear as day.
    

The hell it is. I find it quite confusing. I'll take the Python 2 solution
anyday, which clearly seperates _what_ is called from _when_ it is called. One
of the main problems with the 'my language is so flexible' approach is that
inventing concise solutions becomes a goal in itself.

~~~
steveklabnik
> which clearly seperates what is called from when it is called

You're passing some code as an argument to a function. Many other languages do
this. Do you hate Lisp and Haskell, too? Do you not use continuations in
Python? Or callback functions?

~~~
Confusion
If you pass a function as an argument to a function, you're still separating
_what_ from _when_ : the function declaration shows _what_ ; the invocation of
the function shows _when_. It doesn't matter whether it's

    
    
      def foo(f):
        f()
    

or

    
    
      (define (foo f) (f))
    

That has nothing to do with annotating a function to show it binds to some URL
and is invoked when an HTTP GET request is received with that URL. I don't
like having to scroll through a source file to discover such bindings and I
actually prefer them to be defined at a separate place. In that sense, the
Python 2 solution isn't good either and suffers from the same problem I
described earlier: people try to be so concise that they loose sight of other
goals.

~~~
steveklabnik
The Ruby code is not an annotation. It's very close to passing an anonymous
function to a function. The definition of get is

    
    
        def get(path, opts={}, &block)
    

See that &block? Here's the actual source of get:

    
    
          # Defining a `GET` handler also automatically defines
          # a `HEAD` handler.
          def get(path, opts={}, &block)
            conditions = @conditions.dup
            route('GET', path, opts, &block)
     
            @conditions = conditions
            route('HEAD', path, opts, &block)
          end
    

Think of it as "I'm registering this block as a callback, to be called when
this url is processed." I'm not sure how else you'd like to have a web DSL
written; every web library I've used has worked this way.

~~~
Confusion
_The Ruby code is not an annotation._

Which is exactly the problem: it should be, because it is meta-information
about when the function is supposed to be called. It's not a good idea to wrap
that into a function, together with the code that is supposed to be executed,
because you are mixing two completely different kinds of information into some
new function. This code is being too clever for it's own good: it condenses
information so far that you are forced to think harder about what each piece
means. I consider this is one of the main dangers of languages like Ruby: it's
proponents lose sight of the fact that they are coming full circle, back to
writing code that's so clever that no one in the future will understand it.

 _every web library I've used has worked this way._

I doubt that we've used a disjoint set of web libraries, so my only answer can
be: no, they haven't worked that way. Most libraries map paths to named
functions separately from implementing the functions.

Conciseness is not an ultimate goal; in fact, it is rather the opposite, as
those that suffered under the clever C hacks of others will tell you. To
paraphrase Santanyana: people have forgotten the past and are repeating it.

~~~
steveklabnik
I guess we'll just have to agree to disagree on this. By keeping the function
definition near the route instead of just defining a name, I feel that it's
much, much cleaner.

> I doubt that we've used a disjoint set of web libraries,

I guess I mis-spoke slightly. I meant assigning a function to a route, because
I consider that (in this case) it's an anonymous function to be an irrelevant
detail. Basically, to me

    
    
        get "/hello", hello
        def hello
            puts "hello"
         end
    

to be the as clear or less clear than the way Sinatra does it. Rails and Zend
(the two frameworks I've used the most) put that 'def hello' in another file,
elsewhere.

Anyway, thanks for the discussion. We've apparently boiled it down to taste,
so it's a good thing there are multiple languages, I guess.

~~~
Confusion
Thanks to you as well :). I even may come to see it your way in the near
future, as it seems I'm going to be doing some Ruby coding for my new
employer.

------
mark_l_watson
A main take away point: Ruby is better for writing DSLs (which is what I am
doing for one customer right now)

~~~
stcredzero
Smalltalk is even better. Advanced Smalltalk _is_ morphing Smalltalk into a
DSL. You can even write your own domain specific if-then-else analogues, and
it looks 1st class like the Standard conditional logic. Yet the implementation
is just a plain vanilla method.

~~~
gnaritas
You can't morph Smalltalk into a DSL as Smalltalk itself is nothing but a DSL;
syntactically every single control structure is library.

~~~
stcredzero
I prefer to think of it this way: DSL are syntactic 1st class citizens in
Smalltalk. (Not 1st class for optimizations, though)

To say Smalltalk IDS is a bit useless. Sure, if your "domain" is some Turing-
complete language.

~~~
gnaritas
> Sure, if your "domain" is some Turing-complete language.

Which is exactly what Smalltalk is. Pick any other domain, and you can use the
same syntactic elements used to build the base language to extend it into that
particular domain.

Ruby DSL's control structures tend to look nothing like Ruby the language's
control structures; Smalltalk DSL's control structures look exactly like
Smalltalk the language's control structures.

------
cturner

        Python lambdas are limited to one line and can’t contain
        statements (for, if, def, etc.). Which leaves me
        wondering, what’s the point?
    

As much as I wish that the python lambda syntax was more powerful, they are
ridiculously useful for one-liners where you can't use forms that require
whitespace indentation. Everything must consist of set operations.

    
    
        cat file | python -c "import sys; lines=sys.stdin.readlines(); lines_i_care_about = [str(l.split(',')[2]) for l in lines if l.split(',')>=3]; print '\n'.join( lines_i_care_about )
    

(yes you could do this example in awk or sed, but that's not the point)

~~~
grandalf
As others have pointed out, you could just use a non-anonymous function
defined in the current scope in place of a lamba...

------
joblessjunkie
"Lisp chainsaw"?

Definition or reference, anyone? Although I can probably guess where this is
leading....

~~~
madair
It's a play on the old description of Perl as a _swiss army chainsaw_

------
angelOS
I hate this stupids discussions and I have seen many pythonist criticizing
ruby..why?...because think ruby is a rival?...I use java and ruby..one reason
for never choose python is his fanboy community w close mind and always
criticizing the other languages..like java..c# ruby...yes..your language is
better and is perfect but not everybody prefer it...if you learned a language
only for speak bad of it is better no learn it, when you has a few days using
ruby is than understand all thing back it...star type code without parentesis
and see it look better and is most readeable (I remember you I come from
java), I use a bit python and his syntaxis is good but i don't like
all...never I feel good using it (I feel more limited) but I don't writte a
article criticizing python, ruby is the language for peoples without limits
and free mind, RUBY IS THE MOST ELEGANT LANGUAGE I HAVE KNOW, and is very
readeable (no exceeds python but is very readeable) for all other reasons I
think python could win the discussion forget this discussions and allow
ourselves know new ways to learn and write, this discussion are like the
religions discussion, nobody win and only works for create bad ideas for the
others...peace and sorry for my bad english, I'm germany

------
AdamN
I believe Python has a yield statement, or am I missing something?

[http://docs.python.org/whatsnew/2.5.html#pep-342-new-
generat...](http://docs.python.org/whatsnew/2.5.html#pep-342-new-generator-
features)

~~~
eru
Indeed. Perhaps the Ruby one works different?

~~~
rtomayko
Yep. `yield` in Ruby is a normal anonymous method call. It pushes a new frame
onto the stack. `yield` in Python works more like Ruby's
[Generator]([http://ruby-
doc.org/stdlib/libdoc/generator/rdoc/classes/Gen...](http://ruby-
doc.org/stdlib/libdoc/generator/rdoc/classes/Generator.html)). It freezes the
current stack frame's state and resumes execution somewhere else, returning
again to the same place on the next iteration. They're very different things
really.

More about Python's generators here:

<http://www.python.org/dev/peps/pep-0255/>

~~~
AdamN
So what would yield in Ruby be like in Python? Surely there must be some
analogue?

~~~
rtomayko
You can pass an anonymous function or lambda:

    
    
        def foo(thing, block):
          thing = "cruel " + thing
          block(thing) # like `yield thing' or 'block.call' in ruby
    
        def bar(thing):
          return "hello " + thing
    
        foo('world', bar)
    
        # or:
        foo('world', lambda x: "hello " + x)
    

Ruby's blocks are really just sugar for passing an anonymous function in the
last argument and yield is just sugar for calling that function. The example
above in Ruby would be:

    
    
        def foo(thing)
          yield thing
        end
    
        foo('world') { |thing| "hello " + thing }

------
pheinberg
Nice article. One correction: python _does_ have 'yield'.

