He mentions Python's GIL (which makes multi-threading completely useless), but Ruby (even 1.9) has a GIL too [1] that works exactly the same (awful) way. Ruby 2.0 will have it too [2]. A new Python implementation, unladen swallow is developped by Google to adress exactly this issue. Python-stackless avoids this problem, but the paraigm change is huge, 'normal' code has to be largely rewritten for stackless.
Note that, if I correctly understood, python event engine Twisted uses a custom C-implemented event loop to avoid this.
The GIL (in Python, can't speak about Ruby) is a controversial issue because people assume its bad and Python is therefore bad at concurrent programming etc. Without the GIL, the implementation would be drastically more complex and slower because all built in datatypes, dictionary lookups (for method lookups) etc would need to be made atomic, through locking. I think I can live with the GIL in this case - use threads for asynchronous (rather than parallel) code and use processes (and Python 2.6's multiprocessing library makes this easy) for parallel code execution.
Having said that, I welcome Google's unladen swallow and hope they succeed in removing the GIL.
That's not strictly true. Take a look at http://plausible.org/nasal for an example of an interpreter (mine) in the same broad space as Python and Ruby, yet without a global lock for anything but garbage collection (fixable -- there's no reason in principle preventing a concurrent GC from being dropped in). In tests of CPU-bound code without excessive allocation, it scales to 4-way SMP without trouble.
"""
Python has a GIL as opposed to fine-grained locking for several reasons:
--- It is faster in the single-threaded case.
--- It is faster in the multi-threaded case for i/o bound programs.
--- It is faster in the multi-threaded case for cpu bound programs that do their compute-intensive work in C libraries.
--- It makes C extensions easier to write: there will be no switch of Python threads except where you allow it to happen (i.e. between the Py_BEGIN_ALLOW_THREADS and Py_END_ALLOW_THREADS macros).
--- It makes wrapping C libraries easier. You don't have to worry about thread-safety. If the library is not thread-safe, you simply keep the GIL locked while you call it.
"""
Not really. Stackless Python still has a GIL, and if you want to make use of multiple threads, the GIL will still bite you.
Stackless allows you to write coroutines and has lots of cool abilities, but avoiding the GIL is simply not one of them as far as making use of multiple cores.
Why is everyone so concerned with multi-core concurrency withi languages like Python and Ruby? Adding another processor will get you, best case, a 2x speedup. Rewriting in, say, OCaml or Haskell will get you a 25x speedup.
I quite hoped to be reading an in-depth comparison, but this article merely scratches the surface. What I would like to see from an in-depth article is actual code implementing stuff, showing the features a language has (and comparing them with each other).
I don't think this is a good article nor a useful one.
+1, the article is a 10-minute gloss at best and has virtually no content or analysis.
I mean come on, just look at the 'conclusion':
These languages are interchangeable, especially for building web application. Neither are more awesome. They get the job done and they make programmers happy.
I'd agree with the conclusion, but I'd also agree with nudded - the article is nearly free of useful content. Listing popular libraries of each language does not a comparison make.
In fact, Python and Ruby both are very high level, multiparadigm (oop, procedural, functional, ...) dynamic languages and the difference between them is pretty small. One is a bit more perlish, and one is focussing on a clear, deterministic syntax. Thus, I think the conclusion easily generalizes.
As one wise man once said: Wether you prefer Python or Ruby depends mostly on which one you met first.
It is intended to be a gloss over of functionality that I use frequently. If I want to write much more in-depth comparison then I would have written these (which I may in the future, these kind of blog post takes time to write):
* Beautiful Soup vs Nokogiri/HPricot
* Fabric vs Vlad
* Paste vs Mongrel performance using proxy pass behind Nginx
* (I am not going to write Rails vs Django)
The conclusion isn't wrong, but the content is weak for the evaluation.
At this point in the Ruby VS Python conversation, my expectations for an evaluation are benchmarks of code that is algorithmically identical. If one language provides for a better algorithm than the other, I'd like to see those differences as well.
I intentionally downplay what Python has to offer. It is true that Python has greater breath than Ruby in terms of communities, especially outside web world.
If I started to mention those, it will make Ruby looks less capable (or I would naturally skew the article biased towards Python).
Hopefully you recognize that you misrepresented Ruby throughout the post, in some parts quite dramatically and strangely; the "Modules (for Web Apps)" section is a remarkable mess, listing a random handful of libraries, some of which have nothing directly to do with web development, some of which are components of others, and all representing only a fraction of what's available.
I also see that you were apparently unaware that lambda exists in Ruby until someone in the comments told you, which makes me seriously doubt that you've even used the language at all.
Googling around for info on a language with which you have limited or quite possibly no experience is not a basis for purporting to present an "in-depth" comparison, nor does it qualify you to make claims about capability of a language.
If you read both paragraphs in the Web App section, I made almost immediate comparison between the two:
* (Django, Pylons vs Rails, Merb)
* (web.py vs sinatra)
* (Beautiful Soup vs HPricot)
* (Paste vs Mongrel)
* (Moneta vs Shove)
* (Psyco vs RubyInline)
I would defend myself and say that all these modules are useful for web development. For example:
* You never had to scrape other site's HTML and parse the elements for useful information?
* You never curious about hot-and-shiny key value databases for work?
* You never felt like a certain function could have been optimized and make your web app faster?
Especially in these two paragraphs, I actually use all the ruby modules I mentioned in those paragraphs (minus merb & DataMapper), and I use all the Python modules mentioned as well.
For other non-web related or modules that I haven't use frequent enough, i set it aside and "downplay" it in the article.
Lastly, no amount of blog post could do justice on these two languages. The best way to know about these languages is to use it to hack on something.
"I would ... say that all these modules are useful for web development."
It's very unusual for a web developer to work directly with RubyInline. It's quite a stretch to classify it as a "web development tool" or significantly related to "Web Apps."
"I made almost immediate comparison between the two"
It's not even close, though. The Ruby analogue to WSGI and Paste is Rack, not Mongrel. RubyInline and Psyco are very different things. HPricot is one of multiple options for HTML parsing in Ruby (nokogiri, scrapi, scrubyt). There are multiple JSON options for Ruby (including yajl bindings), and half the paragraph is about simplejson vs python-cjson, which has nothing to do with Ruby. There are also multiple Ruby templating systems available (erb, erubis, haml, markaby, liquid), but you only mention python templating enigines.
And all of these are just a small subset of libraries that you can have in a typical web app, such a small subset that they aren't really representative of anything.
"You never curious about hot-and-shiny key value databases for work?"
There are a whole slew of libraries for "hot-and-shiny" data stores (there are at least 5 Ruby libraries for couchdb alone) and it's not uncommon for people to roll their own. I don't think shove even supports anything "hot-and-shiny" like couchdb, tokyo, cassandra, etc.
"The best way to know about these languages is to use it to hack on something."
"intentionally downplay" is a bad choice of words, sure, but I think he means "am only comparing web stuff". Most web developers do not care about SciPy. Most research scientists don't care about web frameworks.
(Edit: and this is downmodded too? Did Programming Reddit change their color scheme again?)
Well, I downmodded that comment because I took it as the author saying he'd deliberately left out information so as to support the conclusion he wanted to reach. Which is both dishonest and at odds with the stated goal of an "in-depth" look at the languages.
The PLEAC codebase was new to me. It reminds me of the idiomatic python reference (http://python.net/~goodger/projects/pycon/2007/idiomatic/han...) I've found very useful, but haven't delved into PLEAC to see if the coding examples are truly idiomatic.
"Reflection a.k.a Meta Programming a.k.a Monkey Patching"
Really? These are all the same thing? I think not.
"Python comes with webbrowser, urllib2, smtp, http, SocketServer, HttpServer, and more, while Ruby only has net/HTTP"
Untrue. Seems the author knows Python, and spent a little time with Ruby.
More useful points to make would have been how objects are implemented, how inheritance and mixins are handled, and the key paradigms in the language (e.g., in Python, foo.bar() means invoking the method bar; in Ruby, it means sending foo a bar message.)
That is correct, they are not the same thing. That statement is coming from my use case, where I, have so far, only use them for manipulating objects during run time.
Be it calling function, setting attributes, or adding extra functionality by including modules.
"That is correct, they are not the same thing. That statement is coming from my use case, where I, have so far, only use them for manipulating objects during run time."
So here's my main complaint: If you know that these things are not really the same, why do you present them as if they were? You would have had a much more favorable reaction had you been more upfront on your biases, limited Ruby experience, and narrow focus for comparison.
Because in my eyes, they all serve this purpose: "That means you have access to the inner working of an object."
Whichever technique I choose to use does not matter.
I am using my blog the way blog is intended to be used, as opinion piece, I had no attempt in hiding my biases, but there's no need to purposely be biased as well because I like both and make a living out of both.
RE daemonizing, Ruby 1.9 does have a nice Process.daemon function (this is what the author is hoping for?). I'm also a big fan of the 1.9-introduced spawn() function. Not only does this make it easy to create background processes, but via its :in, :out, and :err options (also now found in system() and exec()) it's pretty easy to pipe one spawned process's output to another.
OTOH, I'm a big fan of the What's New in Python X.X articles. Nice features like spawn() seem to sneak into the Ruby codebase unheralded and practically unnoticed.
"Testing
Ruby wins a lot of TDD practitioners. There are plethora
of Ruby modules created for making testing experience
truly wonderful. See: RSpec, Shoulda, Factory Girl,
Selenium."
Yes, testing in Ruby is absolutely wonderful. It makes writing tests an enjoyable experience compared to pretty much any other language I've used. Nowadays I strive for 100% C0 testing coverage and near-100% C1 testing coverage whenever I write software. This can be done very easily in Ruby but is hard to very hard in most other languages.
But anyway, "100% code coverage" is very misleading. Sure, every branch might have been executed once, but you don't ensure that every combination of branches executed once. If you have state that can be shared between code paths, then you are not doing an adequate job testing.
(This is why people like functional programming. One input always produces the same output, cutting the number of cases you have to test dramatically.)
Writing tests is only good if people actually run them.
The default configuration for RubyGems doesn't run unit tests. Therefore unit tests provide a sophisticated check for, "Works on my machine" but isn't so helpful for getting good bug reports about what doesn't work on other people's machines. By contrast the default configuration for Perl's CPAN runs unit tests before you install anything, and this has been the default for Perl modules since the last millennium. (Actually unit testing has been part of Perl culture since 1987! Yes, the "make, make test, make install" idiom was in the first release of the Perl core. This was over a decade before Kent Beck began popularizing the idea for a broader audience.)
And it doesn't end there. For instance the Ruby world has no real equivalent to CPAN Testers. That's a distributed group of people who run all of the unit tests on all of the CPAN modules on different platforms and make publicly available reports of success/fail. That project runs nearly a half-million test suites per month. Which makes it possible to do things like dependency analysis on CPAN modules to track down who is causing what other modules problems. See http://ali.as/top100/.
In short I'm glad that you're doing unit testing and like the tools that Ruby offers for it. However if you're open to cross-pollination, there ARE things you can learn about unit testing from other language communities. Some of them might be great additions to Ruby.
> eval()/exec() are simply evil in both languages. They make debugging more difficult.
I stopped reading at this point. More complicated debugging is a reasonable tradeoff for intuitive APIs. To call them evil indicates the OP is quite inexperienced.
I'm currently working on a python web project; the lack of a mature, battle-hardened payment library kills me.
Ruby's ActiveMerchant is a well-crafted bit of code. The handful of python contenders I've discovered are (1) immature and often poorly coded, and (2) unable to touch ActiveMerchant in terms of number of supported gateways and features supported per gateway.
Certainly, it is an arbitrary python function, so the resulting foo might be a dictionary or whatever. But this doesn't push it closer to the visitor pattern.
Certainly, you can use decorators as a tool to implement the visitor pattern by implementing some hairy, magical reflecting class-decorator which adds a method visit to an object, which then calls visit_{CLASSNAME} on the parameter, but this is just a way of implementing this and not the visitor pattern in itself.
I think it's pretty clear that one person isn't going to be able to write the article we're all actually looking for. We need to get two experts together, one in each language, and in the spirit of respect and discovery, have both people put their language's best foot forward, to try to "get" the other language but to not descend into endless wankery about the details.
But, honestly, I know how it would turn out: The technical considerations are not all that different. Most people who bitch about one of the two and praise the other seem to not understand the one they are bitching about, and the pattern is strong enough at this point that it should be considered the norm. I'm tired of Ruby advocates who seem unaware that yes, Python can pass functions as first class arguments and yes, that pretty much is a block, and tired of Python advocates who get shredded in the comments for obviously having only gone through a Rails tutorial.
In the end the big difference is community. I think there is a big difference there. I'll skip igniting a flamewar by trying to characterize the communities, since it is impossible to do that neutrally, but there's definitely a difference I can see.
Guido van Rossum on inclusion of 'reduce' in Python 3.0, in 2005:
"This is actually the one I've always hated most, because, apart from a few examples involving + or *, almost every time I see a reduce() call with a non-trivial function argument, I need to grab pen and paper to diagram what's actually being fed into that function before I understand what the reduce() is supposed to do. So in my mind, the applicability of reduce() is pretty much limited to associative operators, and in all other cases it's better to write out the accumulation loop explicitly" (http://www.artima.com/weblogs/viewpost.jsp?thread=98196)
Ruby lets you do it however you want to. I don't see myself learning Python any time soon.
Note that, if I correctly understood, python event engine Twisted uses a custom C-implemented event loop to avoid this.
[1] http://www.igvita.com/2008/11/13/concurrency-is-a-myth-in-ru...
[2] http://groups.google.com/group/comp.lang.ruby/msg/e809a7a720...
Wow, seems like MacRuby uses OS threads and completely abolished the GIL [3].
[3] http://www.infoq.com/news/2009/06/macruby-drops-gil-threadin...