From an ex-Pythonista a year in to Ruby, point-by-point:
* Ruby's Unicode support is indeed inferior to Python's; unlike Python, you need to explicitly use library calls to work with UTF-16 strings. Python does indeed bake this in to the language.
* I don't use multiline regexps. On the other hand, I do use normal regexps, all the time, and the fact that I don't have to call out to a library to use them, or deal with special "match" objects with their own API, is a plus. Ruby has more natural support for regular expressions than Python, where regular expressions are an afterthought.
* Ruby's documentation sucks. Full stop.
* I have no idea why I'm meant to care about what this guy thinks of Ruby 1.9 or Ruby 2.0. There's a Ruby 2.0?
* Python is way faster than Ruby. Not by a little bit.
* Ruby's scoping rules are a dream compared to Python's; it support real closures, instance variables and methods with encapsulation, and coroutines that were designed for more than just iteration.
* Ruby and Python are equivalent when it comes to internal consistency. Python delegates virtually everything to a sprawling standard library for which there is, most certainly, "more than one way to do it". Calling out the difference between "print" and "puts" is particularly amusing if you know how Python handles the same distinction.
* Ruby has a cleaner object model than Python, where virtually every feature of the language appears to have been built by exposing the raw symbol table to the language. The simplest way to observe the difference is by taking an existing class and wrapping it with an object that catches all method invocations, a la "method_missing".
* Both Ruby and Python support keyword arguments by giving functions a dictionary type of keyword/value pairs; Ruby has the added benefit of a Symbol type, like Lisp and Smalltalk. No Ruby program fails to use them.
* I'm guessing about, oh, zero people on Hacker News give a shit about SAP support.
* I never noticed that Ruby didn't print the actual line of code that threw an exception. It's true! Python does! I never noticed that, either! That's pretty neat.
* Apparently, despite having been largely ported from Rails, Pylons is more mature than Rails. Awesome.
It is supposed to work this way for some good reasons. But! Enough people have had the same problem as you that new versions of Ruby behave the way you expect.
Help me understand: what are the good reasons for the parameters of a block overwriting variables in an enclosing scope?
That is, we are talking about:
i = 100
x = 0
[1,2,3].each { |i| x += i }
I understand why it is incredibly helpful for x to refer to a variable in the enclosing scope (even if we could accomplish this same effect with a fold). What are the use cases for the parameter i referring to a variable in the enclosing scope?
You can't pass more than one block literal to a method. But you can certainly pass multiple blocks; they're objects, just like anything else. Just add the token "lambda" to your expression:
It's good to see that an upgrade to approximately the power of CL is possible in this case. Still, I feel a little let down. When I first saw Ruby block literals, I said to myself, "Hey, that's a great, concise syntax for lambda. Languages really are getting more lisp-like all the time." But now I know that Ruby block literals aren't really lambda. It does look like Ruby lambdas really are lambdas, though.
This is confusing, because Lisp doesn't have the literal notation you're talking about. Since Ruby supports arbitrary lambdas using "lambda" notation (something Python does not support), it seems like Ruby's syntax can only be be better than Lisp's in this regard.
Programming languages should be designed not by piling feature on top of feature, but by removing the weaknesses and restrictions that make additional features appear necessary. I do not think Ruby is better for having an additional syntax (block literals) that is just like an existing syntax (lambda) only more restricted.
The syntax isn't meant to be "a better lambda". The syntax is meant to recast other language functions, like looping and iteration, in terms of messages and anonymous functions. Since idiomatic Ruby basically never has "for" loops, despite their easy availability in the language, I'm going to go ahead and call the "block" expiriment successful.
If it's meant to recast certain language functionality in terms of anonymous functions, why didn't they just make block literals return anonymous functions? It still strikes me as an almost-could-have-been-great syntax.
Idiomatic Scheme basically never has "do" loops, despite their being part of the core standard, and it's been that way for decades.
Of course there is: if you couldn't access variables in the enclosing scopes, blocks would be drastically less useful. Ruby uses anonymous functions where Python would use a loop construct.
Today, I'm writing in Python, because Python has interfaces to the Win32 COM object for WinDbg's KD.EXE, and trying to make that interface work in Ruby cost me a day of x86 runtime code generation.
I'm not hating it, because despite all the stupid arguments, Python and Ruby are basically the same language.
But why do I still use Ruby? Because builtin Unicode doesn't matter to me that much, I can often answer questions from the Ruby source code faster than I can from Python's hard-to-search documentation, evented code in Ruby and Python is equivalently fast and everything else I do in C, and none of the other complaints from this article were valid. Against those points, Ruby's block construct is a huge win.
I couldn't disagree more. Having tried both platforms, I felt like I was coding with one hand tied behind my back when I was learning Python, Pylons and Django. Web tools and the stack is a lot less mature than RoR stack and the amount of various plugins/gems available for both platforms was not even close. RoR plugins were so much more mature and multitudinous that after we started planning our app, we realized that we'd have to spend about 6 months(!!!) just writing the functionality in Django/Pylons that we were getting for free with Rails. Now this was about one year ago so things might have changed.
Since I don't have the time to go over each point that the author makes, I'll concentrate on a couple.
Lack of Unicode in Ruby 1.8.x. OK, so this might have been an issue before RoR 1.2 came out but since 1.2, RoR has introduced Multibyte and has been a lifesaver. Now, I don't have a clue how many Rails Unicode apps the author has written in his career but I can tell you for a fact that Unicode is not an issue in Rails anymore. We have an app in beta that uses Unicode for every string that we handle and we handle so many strings for so many languages that your head will spin. We haven't had any huge issues with RoR's Unicode support at all. So that argument is really a moot point.
As for language performance, who really cares?! Programmer's time is so much more expensive than servers so the last thing I worry these days is how fast some specialized benchmark runs. As long as the latency is acceptable and you can solve the problem by parallelizing it, the performance of an interpreter is completely irrelevant.
I think his point about performance was more that the rails developers were not taking significant steps to improve it. From what I understand, they are doing this for Ruby 2.0.
He definitely addresses the programmer time thing a lot, except from the perspective of code readability instead of keystrokes or whatever other metric you might use. Python is generally a much more readable language, and might make for more maintainable large scale systems because of it.
>From what I understand, they are doing this for Ruby 2.0.
In less than a year's time, you'll have so many choices to choose from. Ruby 1.9 is just one of the Ruby interpreters that you'll be able to pick from. There's also Rubinius (which is already outperforming MRI on so many benchmarks)
And you'll also be able to choose from JRuby and IronRuby. The way I see it, I think there's more work being done on improving Ruby's than Python's ecosystem.
Ruby people should be more candid about the performance situation, which is a catastraphuck. It is worth it, it will probably get better, and raw performance isn't that important for I/O bound apps, but Ruby is noticeably slower than pretty much all its competitors.
People make this claim all the time but I never hear anyone talk about actual examples where they were bitten by this.
People especially like to harp on the speed of ruby as a knock on ruby on rails. However I have not once run into a real life situation where the performance problem was directly related to the raw performance of Ruby. I have though run into plenty of performance problems:
* At Odeo (RoR circa 2005) we had plenty of problems with memory leaks in our FCGI (this was 2005!) processes and in feed_tools (well known to be slow)
* At my next company we quickly ran into situations where pages were slow to load due to the sheer number of database calls. When I started doing web apps I can remember never having more than three queries behind any given page. Some of our pages were doing 500 queries. This was easily fixed but Rails definitely tempts you to put up scaffolding which you then have to rework once it starts getting real use. In my experience this is a good thing. I'm twice as likely to throw away the scaffolding than I am to have to rewrite it.
* Twitter, which is the poster child for RoR scaling issues, actually actually has had almost all their problems on the backend, having to rapidly change their database and message queue architectures and deal with flaky service providers (AOL and phone companies). Again nothing to do with the architecture they launched with.
So, in the lab Ruby is a slow language, but in the real world how is this biting people?
Like I said earlier, our app parses with racc, does cryptography, and a fair bit of analysis. It is not heavily database dependent. Most of our I/O is memcached. I assert without evidence that Ruby's performance deficits have in fact bit us.
Well, this was interesting. My team just finished a Rails project that used Racc extensively (with multiple different grammars), made extensive use of cryptography, and spent several weeks up on blocks being tuned with ruby-prof.
Obviously, it also used ranges, keyword arguments (like every other Ruby program ever written), strings and string conversions, blocks, private methods, and yes, even Unicode.
I did notice that the documentation for these features was lacking. What I didn't realize was how much Ruby sucked, compared to Python.
I am now steeling myself to begin typing "self" in front of every instance variable, write ten lines of code every time I need a "method_missing", fish the gettimeofday equivalent out of 19 different libraries that return and manage time, re-learn whether I want to call popen, popen2, popenN, or create a Popen class, wrap my data types up in a list when I need code to close over them, condense all my anonymous functions to single expressions to work around Python's accidental support for lambdas (which, according to GvR, are evil), write my oh-so-thread-safe-code for an interpreter that serializes around a global interpreter lock, pretend that my classes have private methods by naming them differently, just like I do in my object-oriented C code, marvel over the amazing things I can accomplish with "generators", continue to format strings using "printf" semantics the way Kernighan and Richie want me to, and track down bugs that are literally invisible due to semantic whitespace.
I haven't found the argument about backwards compatibility to be true of Python, but it has been true of Perl. Code that I wrote 5-6 years ago in Python has needed at least three updates to run in newer versions of Python (1.5->2.0 and 2.0->2.2 and 2.2->2.4--I no longer work in Python, so I don't know if they'd need an update to run on newer versions). On the other hand, code that I wrote ten years ago in Perl still runs unmodified on Perl 5.10. The only major upgrade problem I've seen has been the introduction of native Unicode in Perl, which caused anything that assumed scalars to be made up of 8-bit bytes to break, but that's a pretty broken assumption, anyway.
So, in short, I don't think Python is exactly a paragon of backward compatibility. It may be better than Ruby, but it isn't a solved problem.
I also disagree with the assessment that TIMTOWTDI is a bug. But, me being a Perl coder may have warped my judgment. I find Ruby very intuitive--moreso than Python, even though I've written more Python code than Ruby.
That said, there are some serious deal-breakers in Ruby. Lack of Unicode is one of them. I wasn't among the folks criticizing Arc when it didn't have Unicode at first release...but if it had gone more than a year without Unicode, I would have joined the bandwagon of critics. And, once again, I think Perl has solved Unicode better than Python.
I'm going the opposite direction: after having done two non-trivial RoR apps I have a Pylons project on my hands right now. What can I say? Pylons is a baby Rails and Python is a baby Ruby. Language issues aside, Pylons' architecture seem to be a little cleaner than Rails, but even that advantage largely goes away with all these cleanups done in Rails 2.0.
Pylons/Python are more ugly and less complete than Rails/Ruby:
a) Ugliness: passing "self" to each method, deriving from Object all the time and having __foo__() method names is ugly, ugly, ugly.
b) Incompleteness: URL generation/routing and SQLAlchemy are too primitive and require more coding comparing to Rails. Stuff like form_for(Model.new) isn't possible as far as I can tell. Moreover, Pylons application requires a lot of bootstrapping to get going, setting up DB access is especially tedious comparing to ActiveRecrod's magic. Ralis' soft inforcement and helpers' assistance with RESTful controllers can't be seen anywhere in Pylons as far as I can tell. The list goes on: Pylons is more like a very very old Rails version distorted by ugly Python's object system.
Pylons probably looks pretty sweet to someone who's starting on it with a fresh head, but after two years on Rails I am less than thrilled to work with it. I may not be Pylons expert by now, but man... it's been two months and it still doesn't show me any love :-)
I love Python though. I like CPython implementation and quality of the libraries. Right now it's my language of choice for any stand-alone piece of software, but I try as hard as I can to avoid Python's object system.
b) form_for(Model.new) is great. That's why I've successfully gotten it added in the next version of Pylons. SQLAlchemy is a zillion times more powerful than ActiveRecord, but if you need hand-holding, you can use an AR-ish layer on top of it, such as Elixir: http://elixir.ematia.de/trac/wiki
I've been using Rails for a year and a half, and every time I get a chance to work in Pylons, it's like a breath of fresh air.
It seems to me that the Python fans in this argument are conflating two separate concerns here:
1) Requiring self for access to member variables and methods is a great idea, and is why Hungarian notation like m_foo for a member called foo is popular in languages that don't require it. Ruby does this with @, which is also nice because it's short; I know people who use m_foo in C++ because it's shorter than this.foo, and while I don't agree with them, I can kind of see how a shorter prefix would be nice. But Ruby does lose points in my book for not requiring self/@ for access to object-local methods.
2) Requiring self as an explicit parameter in method definitions confuses the living crap out of newbies. I've seen this several times in the real world. Try explaining it to someone who doesn't yet understand OOP sometime, it's a disaster. On the other hand, making self a magic keyword that gets you the present object, the way Java and C++ handle this, is less confusing, less typing, and has a perfectly nice symmetry between the scope of the definition (method foo is declared on objects of class Bar) and the namespace visible in the call (bar.foo() calls a method foo on the bar object). In contrast, self looks like an explicit parameter in the definition, but doesn't look that way in the call. If you want def foo(self), I think the consistent thing is to do like CLOS and call it like foo(bar) rather than bar.foo(). If you want bar.foo(), something like def self.foo() would be less confusing.
Reason 1: Because they make code easier to read. Purely subjective. I strongly disagree; Ruby is more concise, and ivar access is clearly seperate from method calls.
Reason 2: Because Python will allow you to "cast" self to a superclass to grant explicit access to its variables. Ruby doesn't have this problem.
Reason 3: Because Python would rather overload the keyword "self" than allocate a sigil (@).
The beauty of Python, is that there is a lot of choices when it comes to frameworks. Actually, probably Python is one of the those langues which makes using a framework strictly optional. And there are so many options if you do things that are not your average web app.
With Ruby, you are stuck with one, good framework, but not much if you want to do things very differently.
Django, Pylons, Cherry.py, web.py, Turbogears, and countless of other frameworks.
And I completely agree, on the fact that object oriented programming in Python is not pretty at all, but as a language it wasn't necessary ment to be used that way.
Before picking Pylons I looked at Cherry.py very closely and I actually liked it the most. The reason why we decided to go with Pylons was that it seemed as Cherry.py is being abandoned by everybody in favor of Paste.
But as a lightweight way of exposing Python code to the web I found it very elegant.
He has some valid points, but I think a more accurate title is: "Why I don't like Ruby"
"Migration to Ruby 1.9/2.0"
Won't python dev's have the same problem with Python 3000?
"Performance (or lack of)"
JRuby and Ruby 1.9/2.0 already address this issue
"Scoping"
"There’s more than one way to do it"
I don't see this as a weakness. This is more about style and preference, though I admit I like Python's philosophy better (Ruby code just looks more beautiful to me)
overall I still think it's well written criticism (at times I cringe looking at the horrible stuff people in the ruby community write)
that's assuming the conversion program works well... It may work well for snippets, but I have to see it work well with larger/mature python code bases to believe it.
Ok, that's fair enough. Who knows how well the conversion program will work. Still, for Python 3, there's a clear plan... and there's no clear plan for Ruby 2 (yet).
I've noticed a bias in favour of "What I learned first is better." It applies whether the topic of discussion is programming languages and operating systems or politics and religious values.
(Pre-emption: "bias", not "law".)
Psychologists have lots of fancy words for describing why this is.
These, of course, are not problems with Ruby -- so fellow Rubyists, don't get bent out of shape over this. It's a list of his priorities, which don't happen to align with the current state of Ruby. It's not hard to come up with a different set of criteria that make Ruby look perfect and Python look unusable, and I'm sure other people here will do just that.
But interestingly, all three of his main arguments in favor of Python (more mature, more consistent, and more complete documentation) also sound like great reasons to use Common Lisp over Python.
Ruby has two range operators, .. and .... Why? The only difference is that the shorter one, with two periods, returns a longer range, and the longer one returns a shorter range, not including the endpoint. Can this possibly get any more confusing? 2 The language should have one, not two. It is not hard to add or subtract one when you want a range with, or without, its endpoints.
I like the shortcut. Then again, I like the English language. I like the fact that you can express things in a myriad of (yes, you can say "myriad of") different ways depending on how you want to express them.
A Pythonista friend of mine once complained over the simple fact that Ruby had so many ways to express a conditional but none as elegant as what was used in Python.
Python:
- if foo: bar()
Ruby:
- if foo then bar end
- if foo; bar end
- if foo: bar end # deprecated
- foo if bar
- foo && bar
- foo unless !bar
I love the diversity, however. Really, the first thing that sticks out to me with Python are those superfluous parentheses. Taste, taste, taste.
Its funny someone once wrote that Rails should have been written in Python - his main argument was that Ruby gives you so many ways to do things but Python tends to pick "a" way. The Rails framework tends to follow this Python like mentality of Picking a particular way.
As someone who spends most of his time working in Python, the section called One nice thing about Ruby’s scoping made me a little bit jealous. I hate the way Python handles default parameters.
Also, I think glyphobet is a little hard on Ruby's range objects. He says:
Python’s xrange() can also be passed around like a variable, but you test for membership with value in myrange instead of ===.
An important difference there is that "value in xrange(10000)" iterates to find the value, while "(1..10000) === value" does something O(1), like 1 <= value < 10000. Range objects are handy, and different from list constructors like range() and generators like xrange(). But I agree that the ".." and "..." syntax is weird.
The syntax may be weird at first, but one gets used to it. More importantly, both inclusive ranges and exclusive ranges are useful. It's convenient to have both. It makes code more readable, compared to having to add a -1 offset.
If you're working professionally with RoR buy few commercial books on Ruby and Rails. The cost is negligible when you consider the savings in time that you will get when learn from a good Rails/Ruby book. Sure, Django has a free book on the basics of it and there is Dive into Python series but the number of books on Rails is much greater and they are professionally edited and are of better quality.
The lack of free books is an issue but you get what you pay for.
"You can buy a good book" is not a valid response to "Ruby's documentation sucks". I have all those books, and I don't feel compensated for Ruby's crappy documentation.
I think that the real teller on Ruby is it's own website. not the main page, but most of the surrounding infrastructure linked community is really slow. That is, it is painful to browse. I don't use Ruby or Python very much, but when I do I usually go through the main site for language to find reference and documentation and Ruby is definitely more difficult on that count because of this. I can only assume that it is because they build their websites in Ruby.
On the other hand, Ruby is Japanese. I suppose that the websites may be hosted on on Japanese servers all that way across the and that may account for the lag. It's still annoying though.
Ruby works for me. I like the language semantics. What I miss are the email libraries/parsers that are available in other languages. Don't you think Ruby will catch up with the missing features in a couple of years? The documentation isn't that bad either.
Too much time is wasted on this planet due to people trying to convince themselves they are "doing the right thing".
I don't know (or care) what the results are for others.
For me, Ruby on Rails saves me tremendous time when developing projects and makes me enjoy coding web apps again. So I use it.
If you get that same feeling, use it too. If you don't, try something else.
Anyone who sees anything more to this needs a vacation.
While I agree that Ruby (in the form of MRI) is pretty limited in the kinds of production applications it's ready to support, I feel just as strongly that Python is an evolutionary dead end.
Personally I predict that JRuby (which addresses most of the issues listed in TFA) will become the mainline production Ruby. It runs adequately fast, and has JVM threading, meaning that ceteris paribus it is 'fast enough' for the largely IO-bound tasks that make up web-programming. And when you program in JRuby you find yourself leaning on the Java libraries for most of the heavy-duty stuff (say what you like about Java, I certainly do, but the libraries are abundant and abundantly production-worthy). Ultimately, when you've got lambda and reasonably low-impedance hash tables then you can make everything else, so there's a future for Ruby.
Python on the other hand is a lost cause. Objects are a valid and important ingredient in a balanced diet of programming abstractions, but 'object-oriented programming' is for idiots or assholes or worse. Objects as a first-class language feature are nice-but-optional, I've worked on large C systems written in an object oriented style (one was a simulation, another was a widget toolkit, both had 'object' as a meaningful native domain concept). First-class functions OTOH are not optional, without them you've designed a language for infants. If you are designing a modern high-level programming language and you choose to cripple lambda (either because you've made regrettable decisions about your syntax that prevents their expression, or because you want to put training-wheels on the language itself, or LOL both) then you're an asshole, full stop. Python's scoping is tragic, at least Larry and Brendan had the humility to admit they fucked up and add reasonable scoping. GVR isn't wrong, 30 years of hard-won experience with correct lexical scoping is. If you think Scheme is wrong then I've got news for you: you are. Funny, now that I think about it it's not even about right and wrong anymore, it's about 'Pythonicity', which basically means that not only is GVR never wrong, if you don't agree then you're some kind of barbaric programming-language outsider. God I can't wait for a good example of Python (and more importantly the frigid, self-righteous, under-endowed Python community, I'm looking at you Paul Prescodd) to come into direct competition (- lisp epsilon) in a measurable, documented way.
At least Ruby and Javascript know that (- lisp epsilon) is the place to be, and they're both in the process of trying to add enough curly-braces to make themselves palatable to Java-refugees and no more.
* Ruby's Unicode support is indeed inferior to Python's; unlike Python, you need to explicitly use library calls to work with UTF-16 strings. Python does indeed bake this in to the language.
* I don't use multiline regexps. On the other hand, I do use normal regexps, all the time, and the fact that I don't have to call out to a library to use them, or deal with special "match" objects with their own API, is a plus. Ruby has more natural support for regular expressions than Python, where regular expressions are an afterthought.
* Ruby's documentation sucks. Full stop.
* I have no idea why I'm meant to care about what this guy thinks of Ruby 1.9 or Ruby 2.0. There's a Ruby 2.0?
* Python is way faster than Ruby. Not by a little bit.
* Ruby's scoping rules are a dream compared to Python's; it support real closures, instance variables and methods with encapsulation, and coroutines that were designed for more than just iteration.
* Ruby and Python are equivalent when it comes to internal consistency. Python delegates virtually everything to a sprawling standard library for which there is, most certainly, "more than one way to do it". Calling out the difference between "print" and "puts" is particularly amusing if you know how Python handles the same distinction.
* Ruby has a cleaner object model than Python, where virtually every feature of the language appears to have been built by exposing the raw symbol table to the language. The simplest way to observe the difference is by taking an existing class and wrapping it with an object that catches all method invocations, a la "method_missing".
* Both Ruby and Python support keyword arguments by giving functions a dictionary type of keyword/value pairs; Ruby has the added benefit of a Symbol type, like Lisp and Smalltalk. No Ruby program fails to use them.
* I'm guessing about, oh, zero people on Hacker News give a shit about SAP support.
* I never noticed that Ruby didn't print the actual line of code that threw an exception. It's true! Python does! I never noticed that, either! That's pretty neat.
* Apparently, despite having been largely ported from Rails, Pylons is more mature than Rails. Awesome.