My two big take-away points:
1) It's very nearly a wash. Ruby and Python are so close together (beneath any superficial differences) that distinguishing is almost an exercise in futility.
2) The key thing about Ruby he doesn't like is its "TOTAL, unbridled "dynamicity", including the ability to "reopen" any existing class, including all built-in ones, and change its behavior at run-time." To M's way of thinking, this makes Ruby less "suited for use in large production applications" and more suited for "tinkering."
I don't buy the argument myself, but I will admit that when I first started learning about Ruby, everything I read went on and on about how cool it was that you could open everything up and play. But as I read more, I discovered that the community seems pretty heavily tilted against monkey-patching now. (I may be wrong about this, but it's my impression.) I don't think that means Ruby is for tinkering only, but it does suggest that Martelli's concern is legitimate.
He also offers some nice pasta recipes along the way. (So much so, that now I'm hungry.)
It's absolutely crucial to teams that internalize it's power and pitfalls.
As an aside, I worked on a very large Ruby app (built by about a dozen developers over the course of years) and then later worked on another very large Ruby app of similar size. One of the employees there remarked that it was the largest Rails app built. I think the people who write very large Ruby apps tend to be very quiet about it (no blogs, no open-source, less community participation, etc.) so that if you're one of the ones writing a very large Ruby app you think yours is the largest. :)
The more dynamic (powerful?) the language the more leverage good, experienced developers have. They can achieve results in 10 lines of code that are hard/impossible in more static languages (closures, meta-classes etc.). The other edge of the sword is that one dud developer can bring your whole stack down by being too smart for their own good. The more dynamic the system the greater the risk. In Ruby as is pointed out you can have a developer on the other side of your code base royally screw you because he wants feature X of sequences to act differently.
As with all things it's a balancing act, how smart are your devs, how much time can you spend testing and how strict are your coding standards.
Still worth it though :)
In my experience, teams building Ruby apps tend to be much smaller than teams building Java apps ..
That said, this is a problem for any libraries that you might want to include, you have to trust that the authors followed conventions and didn't do any thing 'evil'. Ruby Rewrite (http://rewrite.rubyforge.org/) was conceived to specifically avoid this sort of problem.
In regards to monkey-patching, while I'm not a Ruby programmer by any means, I sorely feel its absence in other languages. It's in JavaScript (expando objects as well as being able to override and overwrite built-in methods of existing types), and to some extent available in C# (extension methods are a sort-of expando object, but there is very little ability to overwrite a method). Like operator overloading, sure, don't build a project completely off of it (I'm looking at you, C++'s iostream), but when you need it, damn you need it. I'm still delving into Python (late to the party, whatever), but I definitely use Python in much more of a tinkering fashion, so monkey-patching is something I would desire in the language.
I don't entirely disagree with the larger sentiments, but I worry about the tone of the word 'tinker'. That is, the Ruby world is full of playful characters, and often displays a spirit that is far from corporate. However, many Ruby (and RoR) apps are also serious businesses at this point. There are also many libraries that don't charge money, do exhibit that playful or exuberant spirit, but also provide hard-core real-world functionality (e.g., Nokogiri).
tl;dr The word 'tinker' is a bit trivializing (perhaps unintentionally on Martelli's part). The division between 'tinker' and 'enterprise' doesn't fully or properly cut up the problem space. It's a binary view of a multi-faceted world.
(For whatever it's worth, this is my view as someone on the outside of this whole situation. I use Ruby and Perl about equally, primarily for systems administration and personal projects.)
But seriously, at his Q&A session on EuRuKo 2010 Matz mentioned that monkey patching issues are going to be addressed in Ruby 2.0. http://nuclearsquid.com/writings/euruko-day2.html
It's just that Python hasn't ever had an ethos of monkey-patching.
This feature allows you to transform things like "1, minute" into "Minute(1)", enabling dsls, and "wrecking havoc" all over. In ruby, you don't have to do this, as there are simpler and less powerful metaprogramming tools.
So yeah. Just because you have a shotgun, it doesn't mean you can't use it to kill a fly. Of course, the really important question is not if you can, but if you should. And it is always better that this decision is left for the users of the language than to its creators.
I highly doubt he's "ignorant" of anything when it comes to Python...
A better theory is this article is from 2003, but the ast module was added in Python 2.6, which was released in 2008.
(I agree with everything you've said in the second and third paragraphs, but, man, try to give people a little credit before you assume they're ignorant, 'k?)
In Ruby, meta-programming is always powerful and always so easy to use. I don't have problem using these methods, but it pains me when some crappy monkey-patching-flavored gem (For example, cache-money) decided to bite me intermittently.
Or when debugging the code of some kick-ass-ninja-rockstar programmer where he decided to generate methods using both class_eval and instance_eval (along the way, generating the "def statements" using string interpolation) inside a module that supposed to be injected into ActiveRecord object.
I do agree with your last paragraph completely. The real ninja is capable of stopping himself from beheading anyone he sees just because he can.
Is there a good guideline for static method vs. instance method distinction?
In ruby you dont. It's #size and ruby is quite consistent in this respect. So it's remembering a method name vs remembering a function name (in a supposedly OO language).
Also, the parentheses are always optional, not just for zero-argument calls, so he also missed the opportunity to discuss "poetry mode Ruby": a bunch of method calls with no parentheses. Stylistically, "poetry mode" enables the pseudo-DSL style that Ruby frameworks use frequently, but can't really be done in Python.
if baz>10:
func = self.foo
else:
func = self.bar
result = func()
Here func gets assigned something called a "bound method", which has a reference to the object and the method, which you can then apply the () operator and call. I am not a rubyist, but my understanding is that you would use a symbol to do a similar thing. if baz > 10
func = :foo
else
func = :bar
end
result = self.send(func)So, for instance, you might solve it with:
result = case
when baz>10 then foo
else bar
end
This is synthetic, of course. If the goal is to pass around methods, there are lambdas and codeblocks that can be passed around and may fit the problem more naturally than sending yourself a symbol as a message....suddenly wonders if there's a language where both case and indentation are significant.
values, keywords: all lowercase modules, classes, types, constructors: initial capital
For example, it's impossible to declare a class named "string", or a value named "String".
foo { |x| puts x }
Whilst in Python, I need to write: def tmp(x): print x
foo(tmp)
It's not really very nice.The other thing is that Python has no concept of context. In Ruby, I can type:
foo(x)
And it will execute foo(x) for the containing object. In Python, the closest equivalent would be: self.foo(x)
This syntax difference may seem trivial, but it allows you to do some very interesting things to classes. For instance: class Foo
def self.property(name)
define_method(name) do
instance_variable_get(name)
end
end
end
class Bar < Foo
property :x
end
Now the class Bar has a method called "x", without us needing to explicitly define it.Ruby's instance_eval method extends this further, allowing you to execute a block of code in the context of any object you wish.
myfunc <- lambda x: (print x) or x*x # SyntaxError
myfunc <- lambda x: print(x) or x*x # OK in Py3Rather, I'd say that part of the zen of python is: implicit is better than explicit, and I prefer python's behavior in this instance.
I think of Ruby and Python as two languages standing back-to-back in the same spot, mostly unaware of each other, greeting developers who come from different directions.
I started out with Ruby, because of Rails, and just never seemed to quite make it jive with me mentally. When I found Python (because of Django), everything clicked more. I'm not even sure it was the language differences that clicked more for me, or whether it was the documentation, or the code samples, or some other intangible that made it all work.
Just a guess, of course.
When two species fill a different niche in nature, they can co-exists. When they fill the same niche, it is a bitter fight for survival.
+ Newspapers require me to register and login - I go somewhere else.
+ Commercial sites require me to register and login - I go somewhere else.
+ Google requires me to register and login, guess what happens.
I can't be bothered. I've got stuff to write, products to ship, and a life to live. It's just another article. I've saved time by not reading it, and the chances it was useful are small. Besides, skimming the comments has given me enough of the flavor that I don't really think I'm missing much that I didn't get from the comments themselves.
Score another one for the HN community. Thank you.
The only things that are really "different" between Python and Ruby are topical features of the grammars of each, that mostly disappear once the code has been AST-transformed. These could likely be expressed more succinctly in terms of a simple common base grammar, and two small, modular sets of reader macros.
I have been successful at learning a variety of languages. Ruby was difficult for me because it is so similar to Python and yet so different. You have almost the same syntax getting very different results. So if you come from Python you get the exact opposite experience to the principle of least surprise. On the other hand, if you move from OCaml or Erlang there are no surprises because the syntax is different enough that there are no pre-expectations.
Also, metaprogramming in Python and Ruby are quite distinct. The way Python went about it using metaclasses and decorators is very different to the monkeypatching you get in Ruby, so I don't expect the AST results to be that similar for idiomatic code in both languages.
I must admit that I use Python more than Ruby. I like both, but know Python better. I feel Ruby is more consistent though. Either is a good language!
* list(reversed(a_list)) * "".join(reversed(a_str))
and the like.
Python: http://docs.python.org/release/2.5.2/ref/grammar.txt
Ruby: http://web.njit.edu/all_topics/Prog_Lang_Docs/html/ruby/yacc...
ANSI C: http://www.lysator.liu.se/c/ANSI-C-grammar-y.html
Python and ANSI C both have a similar organization of productions and names for statements and expressions. It's pretty easy to follow the grammar to obvious points where the language differs. What are valid unary expressions in Python and ANSI C? There's a production in each grammar that makes a convenient starting point and comparison is easy. What is a valid unary expression in Ruby? It's much less clear.
The Ruby grammar isn't large, so I'm sure some people prefer the way it's organized. Once you've absorbed the whole thing questions like "what's a valid unary expression?" don't matter anymore. But I think it's an interesting distinction to someone trying to decide which language to learn.
Working with Ruby on a day-to-day-basis, I have never reopened core classes and changed anything. Rails comes with some common extensions which simply add new methods, which are less error prone (although I avoid Rails & ActiveSupport whenever possible).
More succinctly: "Ugh! Python? I hate the idea of syntactic whitespace," and "Ugh! Ruby? I have the idea of using @ for instance variables," are both cursory judgments that mask deeper preferential foundations therein.
(But these days, I'm mostly hacking with Arc :p)
I put this question also on Stackoverflow: http://stackoverflow.com/questions/3584945/non-technical-ben...
But if I wrong about this, please let me know.