What Pythonistas Think of Ruby
blog.peepcode.com
blog.peepcode.com
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.
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? :-)
the party line seems to be "this is the way we do
things, if you like what you see, come on in, if not,
no worries"
That is absolutely not the case; Python is the anti-TMTOWTDI. The Python community is very vocal and explicit about the conventions developers are expected to follow, more so than any other language I'm aware of: PEP 8, Zen of Python, non-stop critiques about whether some code is "pythonic" enough.After all, one would have to be a "Rube (that's what [Ruby developers are] called, right?)" to think that Python developers aren't friendly to people who don't worship Python.
There are always bashers. Their existence proves nothing. The question is whether they represent the bulk of the community. It's hard to speak for an entire community, but it is certainly true that the Python community leaders are not into bashing other languages routinely.
you're by far the flamiest person here.
Flamier than the person who called Ruby developers "Rubes" after claiming Python is friendly to other developers? Interesting. Python community leaders are not into bashing other languages routinely
Indeed, this is true. It's unfortunate that so many python developers don't follow suit.> Indeed, this is true. It's unfortunate that so many python developers don't follow suit.
Do you have any numbers to back any of this up? Is it possible that Python just happens to have a small number of really vocal hyper-proponents that feel the need to bash everything else? Could it just be that you aren't a Python programmer so you take more offense to your language being bashed and therefore notice if more often than others?
Does 'Rube' have a negative connotation attached to it?
Yes, and it's been a common insult for at least a century: http://www.google.com/dictionary?aq=f&langpair=en|en&... Do you have any numbers to back any of this up?
We don't need to look any further than this thread: 30 points on the initial Ruby/Rails-bashing rant that also insults Ruby developers, 6 points on tghw's comment that insults Ruby developers with outright name-calling. Par for the course. Could it just be that you aren't a Python programmer
No, considering I've been using python on and off for almost a decade now. your language
Or it could be that there is no "[my] language" and I'm just willing to call out rampant hypocrisy and language-bashing when I see it.Honestly, I find it interesting that people assume someone doesn't use Python just because they call out Team Python on their non-stop trolling and language-bashing. "Either you're with us or against us," apparently. Big surprise.
Yes, it does. Rubyists are typically called Rubyists or Ruby hackers if one does not wish to insult them. Calling a Rubyist ia "Rube" would be like calling a Pythonista a "Pyker" (reference to [piker](http://education.yahoo.com/reference/dictionary/entry/piker), definition 2).
> Maybe I just haven't participated in enough Python-Ruby flamewars to know all of the 'secret' lingo that's only offensive to you if you are already part of that flamewar culture?
There's nothing "secret" about the insulting character of the term "rube".
On the other hand, if you're looking to be offended to prove a point about who is "flamier", you've succeeded.
You lost me here. PHP is the favorite flogging-boy language of a lot of developers from a lot of different environments. Trying to peg this solely on Python developers/flamers is disingenuous. You might as well try to claim that Python developers are responsible for all of the Microsoft (and/or .Net/ASP/C#) bashing that goes on around the web.
Yeah, that's the "this is the way we do things" part, but that's a different issue. Things like PEP-8 and a measure of how "Pythonic" something is helps make one of Python's biggest strengths, the "batteries included" easier to accomplish and easier to understand, because there is a consistent standard. Of course, not all code, even in the stdlib, is up to that standard, but it's more consistent than a lot of libraries you'll find.
The point I was making, and the difference from a lot of language communities I've seen is that there is little of this hyperbolic "That's not even possible in [insert-language-here]" nonsense. The Python programmers I tend to interact with don't really mind if you don't use Python, because at the end of the day, almost every language has the necessary features to Get Stuff Done.
Speaking of which ...
I was, however, saddened by the fact that almost every single time I've seen a Pythonista talk about how nice Pythonistas are, the comment has included a dig at people who use other languages like that. The probability seems to run in the 90%+ range.
In less than 10 minutes after posting anything remotely negative about Haskell, I have a horde of angry fanboys telling me how I am an idiot.
I guess that may (or may not) show that a single language can be part of different cultures.
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.)
... and Perl 6.
Wait. Ruby? What? Did you have a bad experience with some Rails people and decide that Ruby developers hate Perl?
As someone who loves both Perl and Ruby, I haven't seen any Perl hate from Ruby developers in general. I can't vouch for Rails people, though. There are some serious social dysfunctions in that community.
> The only place outside of the Perl community where I can admit to liking Perl (and not be flamed) is #haskell.
I haven't gotten into Haskell (yet) -- but I've never gotten any shit on the ruby-talk list for "admitting" that I like Perl.
> (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.)
Wow. WTF?
I have gotten shit from Pythonistas in person a couple of times for liking Perl, but nothing nearly that bad -- just as I have for preferring FreeBSD over "Linux".
In general, the hackers I know dislike Java, so I haven't really had the opportunity to get treated that badly by a Java developer. Maybe I'm just lucky.
I use both Ruby and Python enough to appreciate that both languages generally make important tradeoffs with good intentions, but I don't always agree with the results (in either language). I also find Javascript often has an interesting relationship to both languages.
Just ask the protestants and the catholics.
However, we can sometimes mistake _subtle_ differences for _small_ ones; but just as there's a substantial difference between the Mac OS and Windows, there's a substantial difference between Catholicism and Calvinism (which was the most successful form of Protestantism) -- the difference between God seeing that you went to Hell, and God sending you there. I could go into much greater detail (I count nine paragraphs in how I'd previously structured this comment), but that's the nutshell of the nutshell.
There's a joke about that, I looked it up:
I was walking across a bridge one day, and I saw a man standing on the edge, about to jump off. So I ran over and said “Stop! don’t do it!” “Why shouldn’t I?” he said. I said, “Well, there’s so much to live for!” He said, “Like what?”
I said, “Well, are you religious or atheist?” He said, “Religious.”
I said, “Me too! …Are you Christian or Buddhist?” He said, “Christian.”
I said, “Me too! …Are you Catholic or Protestant?” He said, “Protestant.”
I said, “Me too! …Are you Episcopalian or Baptist?” He said, “Baptist!”
I said, “Wow! Me too!…Are you Baptist church of God or Baptist church of the Lord?” He said, “Baptist church of God!”
I said, “Me too! Are you original Baptist church of God, or are you reformed Baptist church of God?” He said, “Reformed Baptist church of God!”
I said, “Me too! Are you reformed Baptist church of God, reformation of 1879, or reformed Baptist church of God, reformation of 1915?”
He said, “Reformed Baptist church of God, reformation of 1915!”
I said, “Die, heretic scum” and pushed him off.. — Emo Phillips
Calvinism had _huge_ practical consequences -- in social policy, it's the difference between ensuring that the poor are fed and sheltered, and kicking them into the street; and you can only imagine what it meant for the laws of war...
Edit: And the joke you mention is only too recognizable, but it's more like the Catholicism-and-Orthodoxy situation, where it's a matter of tribal loyalties more than views of the world...
Then again, programming language is a very personal choice for many, so if you insult a language, you insult the person. There aren't many polyglot programmers that are detached from their preferred language.
For me, I prefer Python, but I'm not going to blindly defend it.
Special case in programming -- "colour of the bikeshed" http://en.wikipedia.org/wiki/Parkinson%27s_Law_of_Triviality
I'd like to quotes these cool stuff as well, just need a way to look it up :)
I have to do it, for different platforms, but that means I'm constantly switching between design techniques and I can't reuse one body of common code.
It just makes sense to put all your eggs in one basket and make the switch. However, it's important to have a healthy respect for other languages and their pros and cons compared to your own choice.
(This is less of an issue if I want to use Python and C++. I'll rarely want to reuse linear programming code or a PDE solver in Python, and if I did, I would just wrap the C++. Similarly, I never want to use code I've written for the web in C++.)
Unfortunately because of the nature of the web I haven't seen any real good solution to this yet. At minimum, you're usually dealing with some combination of Python/Ruby/PHP backend and some amount of Javascript/Actionscript on the frontend.
Instead of thinking of code re-use, we're left with a UNIX style resource re-use. Every component can stand alone, but they all work in conjunction with each other and can be re-arranged to work in different ways.
I don't buy this point. I think you're confusing what Zed said about the Rails community with the reality of the Ruby community. Frankly, from what I've seen, the Rails community is a bit of a ghetto within the larger Ruby community.
I've also seen a lot of what amounts to acrimony and vitriol from Pythonistas when discussing other languages, where Rubyists (not Rails developers, specifically, but people in the broader Ruby community) have tended to be much more appreciative of what developers in other language communities, and other languages, bring to the party.
What's the difference between a Rubyist response to a Python way of doing things and a Pythonista response to a Ruby way of doing things? In my experience, the Rubyist says "Hey, that's kinda neat -- but it's not for me," but the Pythonista says "You're doing it wrong."
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".
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.
That people even feel this comparison is appropriate is what has me depressed. It represents a fairly fundamental set of misunderstandings.
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.)
Ergonomic distinctions are useful though, as is the distinction between declarative-style APIs and more imperative ones, which 'DSL' is often used to make.
unless you.talk :like => "this"If you're not doing that, I think they're kind of silly.
That's the same argument for filing the serial number off of TDD and calling it BDD: sometime, somewhere, somehow eventually some non-programmer is going to have to maintain source code without a trained professional programmer around to help.
I don't get it; FIT's been around much, much longer. What kind of non-developer business rule expert can read the punctuation-sprinkled pseudo-English pidgin Ruby spreads around but doesn't know how to manipulate tabular data in a spreadsheet?
I don't really get it, but I'm curious. People I respect swear by it.
There are some out there though, for eg. FancyRoutes: http://www.railsinside.com/plugins/252-fancyroutes-a-nicer-d...
get / 'orders' >> :orders > :index
with route / :slug / 'order' >> :orders do
get > :show
put > :update
end
get {'item_images' => :controller} / :image > :show
That looks like Ruby all over the place. Yeah, it overloads operator methods more than most Ruby code, but it's very clear that it's Ruby.True.
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.
I think that part of the problem is that no one (whom I've seen, at least) has explained in a brief, easy to follow manner just what the Lisp macros get you beyond all of the parse tree manipulation, code generation, and "metaprogramming" you can already do with Ruby. If you could explain the extra benefit succinctly, I'd love to hear it. In other words, I'd love to see an essay or blog post that makes me wish Ruby had true, Lisp-style macros.
Performance, by the way, won't be enough: language implementations are always getting better.
Uh, the stuff you can do with ruby (short of the Ruby2Ruby parse tree generation) is incredibly limited compared to the arbitrary transforms that macros, especially tools like macrolet (lexically scoped macros) and symbol-macrolet (lexically scoped symbol expansion) allow you to do.
Ruby2Ruby lets you do almost arbitrary parse tree transforms, but again it does this at runtime. Unless you specifically architect your program in a somewhat non-rubyish fashion to have a sort of "compile" phase where your transforms are completed.
> Performance, by the way, won't be enough: language implementations are always getting better.
... I say this as a fan of ruby who's made a career out of it for years. Ruby's performance improvements move at a snail's pace. If someone said, "Hey, you can do everything Ruby2Ruby can do, but with 0 performance penalty" then that'd be a huge value add. If you say it isn't, you're being unreasonable. "It is fast enough" is a mantra you can foist off on people who haven't put up production systems on a Merb stack.
Nothing in your sarcastic "Uh ..." missive makes me or anyone else care about the features you just named. Yes, I know Ruby doesn't have True Lisp Macros. The point is, why should I care? What real-world problem can I not solve elegantly in Ruby because it lacks this language feature?
"It is fast enough" is a mantra you can foist off on people who haven't put up production systems on a Merb stack.
Well, seeing as how I have deployed Merb in production as well, maybe we can discuss the merits without trying to measure egos based on who's deployed what?
Again, my point is that if you can't name a single real world benefit of macros over what's already in Ruby, then why should anyone care how fast they are?
It allows for the creation of real Domain Specific Languages and the real extension of lisp for a given problem domain. Do you need constraint propagation on a network of cells? You can make a macro that turns this into an operator in lisp. You can extract nearly any pattern out to the language and begin complex manipulations there.
Since you have a frame of reference I can use, let's talk about rails routes. Imagine if you could specify rails routes in a way at least as naturally as you do in ruby (albeit with more parenthesis, but with fewer line-noise symbols otherwise), but have this become the most efficient implementation of that specific routing table.
You get to have your cake (a syntax that is expressive and immediate) and eat it to (is transformed under the covers into the most optimal code for that task), with frosting (0 runtime penalty for this decision).
> Again, my point is that if you can't name a single real world benefit of macros over what's already in Ruby, then why should anyone care how fast they are?
I say "the language is extensible!" and you say "but what about the real world." Sir, I don't know how to get more real world than this. You use it a billion different ways all the time.
A simple example... I've been working a lot with the JodaTime library in clojure, and I got sick of having to work with the ponderous Java-centric method for building PeriodFormatters (for an example see: http://www.bestinclass.dk/index.php/2010/02/reddit-clone-in-...). So what I've done is write a macro in just a few lines of clojure that lets me say:
(period-formatter days ("day" "days") " "
hours ":" minutes ":" seconds)
If that's not cleaner and more usable, I dunno what is. You only need to write one or two formatters (and typically you need a few) before the macro has "paid itself off" in temrs of line count. And to the underlying code at run time, this code and the code snippet for the formatter from my link are basically indistinguishable. There is 0 runtime cost to this abstraction, but a lot of read-time improvement.Could you do this particular example in ruby? You could do it to some extent, yes. But not without some significant work. Note, for example, that the argument list to the macro needs to be checked for strings after lists of strings, as this case is not directly supported by the underlying formatter.
I think the problem was that until now you weren't giving any examples that explained how Common Lisp macros were giving one any greater ability to do this sort of thing than Ruby. One could say "Ruby allows for the creation of real Domain Specific Languages and the real extension of Ruby for a given problem domain," with only a slight alteration in what one considers "real". As such, saying something like "Ruby doesn't give you real foo" doesn't tell anyone anything about what CL gives you that Ruby doesn't.
Also . . . I totally understand the desire to keep (non-earth-shattering) performance differences out of the discussion. After all, one doesn't use Ruby to write realtime systems in the first place. The performance of its implementations is simply not impressive. If I've chosen to use Ruby for something, I've already thought about the performance implications and decided that the performance penalties of Ruby as compared with something like C (or even Perl) are not limiting factors for the particular task I choose to tackle. As such, it makes sense to say "Please tell me about the syntactic and semantic value of Lisp macros, rather than the performance benefits of a Lisp implementation over a Ruby implementation."
You did, however, get into a little more explanation this time, which is good. I just wanted to point out that your disbelief at the notion that someone didn't achieve enlightenment based on your previous comment seems a bit unwarranted.
Well also Lisp macros are more comprehensive. Ruby can only make DSLs that look mostly like Ruby. In Lisp, you can literally drop in a new parser if you really want to. In fact, the default PLT Scheme DrScheme distribution has an Algol implementation that is basically a macro set (with some special features).
This allows you to inject whole new programming paradigms into your code. If you need a special kind of OO, you can easily create it. This is actually incredibly-hard-borderline-impossible to do in Ruby. Especially when you get into anaphora injection and complex closure manipualtion.
> You did, however, get into a little more explanation this time, which is good. I just wanted to point out that your disbelief at the notion that someone didn't achieve enlightenment based on your previous comment seems a bit unwarranted.
I had the same reaction this morning when a teenager asked me, "Okay so I get pointers. I get what they are. But they don't see good for anything in the real world." If you find this offensive or dismissive, I apologize. I am simply saying that I think you and I are operating at entirely different levels of abstraction, and bridging that gap is difficult for me.
Much better.
I haven't worked much (almost at all) with macros. How easy/difficult would it be to create a Ruby-esque DSL in Common Lisp? I'm just curious.
> This allows you to inject whole new programming paradigms into your code. If you need a special kind of OO, you can easily create it. This is actually incredibly-hard-borderline-impossible to do in Ruby.
Really? I dunno, I've seen (for example) some really interesting functional paradigm idioms implemented in Ruby, such as a lazy evaluation module.
> Especially when you get into anaphora injection and complex closure manipualtion.
I admit I haven't done "complex closure manipulation" much anywhere. I do use closures from time to time in my code, in a number of languages -- including Ruby. I'm not entirely sure how "complex closure manipulation" would look, actually, so I have no basis for comparison in that regard. I guess I'll just have to take your word for it.
> I had the same reaction this morning when a teenager asked me, "Okay so I get pointers. I get what they are. But they don't see good for anything in the real world." If you find this offensive or dismissive, I apologize.
I don't find it offensive or dismissive. I understand your perspective. I just don't think it helped anyone understand anything. I'm sure it all looks a lot more natural to someone who has done a lot more CL and Scheme coding, but it really doesn't to someone who has pretty much never touched a CL or Scheme macro in his life (or even for me, who has touched them a little). In fact, what Lisp macro experience I have is mostly limited to UCBLogo plus a light sprinkling of R6RS.
> I am simply saying that I think you and I are operating at entirely different levels of abstraction, and bridging that gap is difficult for me.
That's understandable. To some extent for my benefit, and even more so for the other guy's, I decided to explain some of where the gap lies -- so that you might find it easier to bridge. I hope.
What I'm hearing (and feel free to correct me) is that the gain over Ruby is not as much about additional expressiveness as it is about providing this expressiveness with equivalent performance to that of in-built language operators. That's fair.
I've used Lisp quite a bit (in fact, I did almost all of my first significant programming in Scheme) and even with that background, I've never bought the claim that Lisp gives you some huge practical syntactical/semantic gain over Ruby's already extremely expressive and extensible syntax. I guess I was hoping to be swayed.
N.B. apotheon's comment sums up my perspective perfectly.
Ruby's syntax is hardly extensible at all. All you're doing is changing the default scope with instance_eval and producing objects with the right intermediate behaviors. You can make some neat little DSLs with this trick, but it's not a real extension to the language.
For example try making the classic anaphoric if in ruby. Can't be done without resulting to cheap excuses like "Well it's a block argument."
It also frustrates me that people have thousands of objections to the pros people put forward for lisp, but no real objections except for an argument about parenthesis that's not even really true anymore. Prefix notion maybe? Oh no your arithmetic is slightly jumbled, everything else is exactly as you use it.
Whatever. The fact is that in Ruby you can easily write a DSL that looks as if it was custom rolled for the domain and task at hand. In fact, you can do it so transparently that people begin learning the DSL without learning Ruby (cf. Rails). If that doesn't mean Ruby's syntax is extensible, I don't know what does. (And, yes, I get the difference between Ruby's implementation of DSL support and True Lisp Macros; it's just unclear that the difference matters in any significant semantic way.)
I thought we were past trying to praise Lisp's features over Ruby's simply by calling Lisp's "real" (where "real" means exactly the same as Lisp's down to the backquotes and preprocessor). That argument is tautological: no language could ever possibly measure up to Lisp with that kind of criteria.
For example try making the classic anaphoric if in ruby. Can't be done without resulting to cheap excuses like "Well it's a block argument."
Raganwald et al seem to have managed just fine.
http://github.com/raganwald/homoiconic/blob/master/2009-09-2...
And deriding the brackets is just as meaningless as someone deriding the parentheses in Lisp. Speaking of which:
It also frustrates me that people have thousands of objections to the pros people put forward for lisp, but no real objections except for an argument about parenthesis that's not even really true anymore. Prefix notion maybe? Oh no your arithmetic is slightly jumbled, everything else is exactly as you use it.
Not my issue. Heck, I like Lisp! That said, I think Lisp evangelists are failing to make a case for it over, say, Ruby for precisely the reasons discussed ad nauseam in this thread.
If by "custom rolled" you mean "laden with :symbols, forced into ruby's function invocation structure."
> I thought we were past trying to praise Lisp's features over Ruby's simply by calling Lisp's "real" (where "real" means exactly the same as Lisp's down to the backquotes and preprocessor). That argument is tautological: no language could ever possibly measure up to Lisp with that kind of criteria.
Except that I don't make that claim. Dylan did it just fine. I'm asking for real modification of the syntax tree. I'm asking for a real extension of the parser. It's not tautological and there are examples in the wild of people actually succeeding here without the classic sexpr syntax.
> Raganwald et al seem to have managed just fine...
Dozens of lines to mimic at runtime what compiler extension just allows it, in a far more natural and understandable way. I didn't say it was impossible, I said it was awkward.
> And deriding the brackets is just as meaningless as someone deriding the parentheses in Lisp.
I didn't deride brackets. I said that these complex runtime proxy solutions are hacks. It's like C++ people arguing they have anonymous functions because they can write Functor classes. It's a non-argument, because it's almost certain that you _can_ accomplish it. The question is, "How much extra complexity do I have to introduce in order to make this desirable way of programming possible."
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.
You may or may not agree, but you'll probably be interested in Why Ruby is an acceptable Lisp: http://www.randomhacks.net/articles/2005/12/03/why-ruby-is-a...
Covered on HN previously here:
FLAMEBAIT -> FLAMEBAIT
Whether it is a good reason, and whether these considerations are sensible, is a separate discussion. Whichever way you put it: they exist and should be acknowledged.
As I sit here writing this, it strikes me that someone who's using these kinds of things to avoid learning Lisp is a lot like the Python newbie who's discovered the language and wanders on to comp.lang.python complaining about the syntactically significant indentation. As with most matters, I'm inclined to believe that Lisp's problem here is primarily a people problem rather than a technical problem.
One of the themes of Gary's talk was that Ruby is more expressive/flexible than Python, and lisp was thrown into the discussion as sort of a "gold standard" of expressiveness/flexibility, without necessarily passing any judgment on overall merits of the three languages.
To the extent that Ruby strives for more flexibility, it is probably way more influenced by Perl than lisp.
As somebody who has used both Ruby and Python fairly extensively, I think Ruby is undeniably more expressive than Python at times, but also more arcane at others. Some of the differences probably come from irreconcilable tradeoffs, where you cannot have your cake and eat it too, but other tradeoffs are probably less necessary, which is why people continue to discuss it. In the case of Ruby, it's a pretty young language, so there are probably opportunities to make it more appealing to a Python mindset without losing its great flexibility, although I do not have specific proposals.
The conference Gary spoke at was a Python conference, so most people were more interested in ways that Python could learn from Ruby, without sacrificing Pythonicness. Gary seemed to reach the conclusion that the number one feature he envied in Ruby was blocks. Speaking for myself, I wish Python just had some kind of anonymous function syntax that was more rich than lambdas, even if it were not exactly semantically similar to Ruby blocks.
A lot of people keep saying this, including the article author, and I'm having trouble understanding why. Lambdas are for "one-liners", functions are for more-liners.
Any time you want to write multiple lines in a lambda it's trivial to make it a named function.
def listSomeTable(name):
print name.center(40, "=")
def getWeirdNumberPair(cap):
while True:
a = random.randint(1, cap)
b = random.randint(1, cap)
if (a==1) and (b==1):
continue
return (a, b)
for i in xrange(20):
print getWeirdNumberPair(i)
print "="*40
What do you want to use multiline-lambdas for that you can't do (equally simply and elegantly) with named functions?Just a matter of taste, mind you, but it's my reasoning for preferring anonymous functions.
In python, although they could technically be done as libraries, from a syntactic point of view, having to declare named functions and pass them explicitly as arguments rather defeats the elegance of the approach.
So instead we have special features and syntax added to the language, like with statements and list comprehensions, which are limited special cases of what can be expressed more generally with a nice syntax for passing closures as arguments.
Not that it necessarily matters, there's always a pythonic way to do the equivalent thing. Although a lot of the time it's more imperative, and my taste is for functional programming idioms where possible.
Second of all, multiline-lambdas are already possible in Python, but they are not anonymous functions.
Anonymous functions, as I said, allow for rich syntax; they do not affect the Turing completeness of the language. The context I am speaking of is "expressibility" in the sense of natural language, not whether or not something is expressible at all.
Ruby allows you to do stuff like this fairly naturally:
def process_event_until_timer_expires # check time, then call block only if # timer not expired end
process_events_until_timer_expires { |t, event| puts t fire_event_downstream(event) }
Having an anonymous function here allows you to read from outside in, which is more natural. From the outside, you know you are in some event loop, then you can look inside the block to see the details of how the event are handled. It's really that simple. Not earth-shattering different than Python, just subtly different and more expressive.
I've been using Python for a decade, and Ruby's still overly exotic to me, so I am sympathetic to people that defend the more Pythonic approach. But Ruby does allow for a different kind of expressiveness here.
Javascript also makes heavy use of anonymous functions, and if you use anonymous functions in other languages, you realize that they have value, even if they are occasionally abused and technically unnecessary.
The problem, though, is that this is entirely a Python conceit. It is in no way, shape, or form any kind of programming truism. In fact, taking a more principles-oriented approach, a named function is really just a special case of a lambda. I think this may be one of those things that using a LISP (such as Scheme or Common Lisp) helps people realize.
This:
(define (foo n)
( . . . ))
. . . is just syntax sugar for this: (define foo
(lambda (n)
( . . . )))
The fact that the syntax sugar is all many languages expose to the programmer doesn't change that fact, and the one-line restriction on "lambdas" in Python seems quite arbitrary.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.
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.
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.
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.
Interestingly I find myself equally baffled when I have to read code with side-effects. There's just so much implicit state (and state changes going on in the background), you have to keep in your head. Pure languages are so much easier to understand.
(My comment about pure languages above was meant to highlight the joys of Clean and Haskell. Curry may also be worth a look. And Prolog, if you dare.)
. . . but if you want to actually use a LISP for practical programming, and you start out with any Scheme, you're going to have to follow that up by learning another (non-Scheme) LISP. You might as well just start out with Common Lisp and be done with it.
Judging by my experience, Scheme is not a language one should set out to learn so much as a language one should learn as a side-effect of going through a book like SICP or The Little Schemer. Trying to do anything "real" with Scheme is an exercise in frustration, especially if you want it to be portable across Scheme versions, since the biggest names in Scheme implementations appear to be entirely uninterested in library portability except where "portable" means "Well, we can use it, and don't care whether you can."
Scheme itself is an excellent language, though. Too bad that, alone, is not enough.
I still haven't done anything with Prolog past using it for prototyping, but it has some really cool ideas, and I hope to have a good excuse to play with it more soon. (And it, too, has some great books.)
"Brevity is the soul of wit."
Therefore I like Python for imperative programming and its extensive libraries and far prefer Haskell to any LISP dialect for functional programming. Haskell is elegant in a way LISP wishes it could be.
Syntax is human and syntax is ergonomics. That's why languages with good syntax are so popular and deservedly so.
At the same time I think the number one reason languages eventually die off is because of syntax. A particular syntax was designed for solving specific kinds of problems. Then people realize there are deeper or different problems that the syntax cannot adequately address. Since the language is not a Lisp it cannot be repaired.
I think Python and Ruby are cool and useful tools, but I don't think their design will last another 50 years as Lisp probably will.
Lisp (or lets say Scheme, because Common Lisp is ugly and imperative) does have some nice points. I rather like the syntax. But e.g. strict evaluation by default and lots of side-effects hamper the expressiveness and flexibility of the language.
I just like to counter those smug Lispians. Lisp has nice syntax, but the underlying semantics is nothing to write home about any longer. Add tail call optimization to Python (and perhaps continuations) and you have something similar to Scheme modulo syntax.
Thats why lispers are smug sometimes, they know that their language will change dramatically in the future to adapt to the new environment, its the source of lisps immortality, it is destined to be reinvented.
Now a post on Python v. Ruby?
It must be Shark Week on HN.
The poisonous snake the stripes are thought to mimic:
http://minuet.dance.ohio-state.edu/~gallo54/images/words/sna...
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...
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.
The reason it gets so heated is that the two languages, while similar from some perspectives, are _wildly_ divergent in philosophy. It really is a Catholic/Protestant battle, as someone pointed out earlier.
And who's who? (Not meant as flamebait. I just want to see where the analogy leads to.)
This particular analogy only runs skin-deep.
Personally, I've always programmed primarily in other languages (C++ being mein liebster Feind) but I've relied a lot on Python (and occasionally Jython) for day-to-day scripting and for delivering code to customers that reorchestrates existing code to do new things. Python has never lit a single creative spark in me, but it has always delivered for me without demanding much in return. Now, that is a statement you will never hear applied to Ruby.
I don't know much about Ruby, but the things I hear about it remind me of Perl in some ways. Back in the day, I spent a lot of time learning Perl, promptly forgetting it, and going back to Perlmonks to learn it yet again. Perl comes naturally for impressionists who love to program by instinct, pattern-matching, and trial-and-error. They love it when something new pops into their head and they type it in and it just works, and they aren't immediately sure how or why. Perl is also for dedicated professionals who want a tool that rewards more study and practice with more and more power -- mastery of Perl is a never-ending road with a seemingly never-ending escalation of power and awesomeness.
Ruby seems to be a much more easily understood language than Perl, but (from the outside) it seems to share Perl's magical flavor and open-ended approach to mastery. Python is better for people like me who want working, understandable code for the smallest lifetime intellectual investment.
That sounds more like programming (which you can teach yourself in ten years) than any specific language.
I assume you have syntactical concerns and syntactical concerns only in mind, as domain knowledge and local style and creative decisions are far more important for maintainability. Even so, I don't believe you. I've seen far too much Python code which uses decorators and generators and list comprehensions to believe that it's un-Pythonic to "write code that a less expert programmer couldn't understand".
And yeah, the language has arguably become less Pythonic as it caters to more expert programmers at the expense of less expert ones. From the beginning, there have been people who claimed that primitive, clear, inelegant code is worse than elegant, concise code that depends on extra language features. Usually that claim has been rejected, but as sometimes happens in politics, the people who care enough to influence the process are not always the people for whom the process is supposed to work. I see decorators as something of a Trojan horse through which Python became more of a language for me (a software developer who copes with, and sometimes even likes, C++) and less of a language for my customers (scientists and engineers). Which is tragic because there are plenty of languages for software developers and not enough languages for people who just need something stupidly simple yet powerful enough for all practical purposes.
Still, despite the erosion of its simplicity, Python stands out for its philosophy of simplicity and its adherence to it. There remains a gulf between a language that sounded a clarion call for simplicity and has slipped a little from its principles and a language that chose the red pill and dove down the rabbit hole basically for the sheer beautiful hell of it.
I'm don't understand what the difference between Scheme circa 1975 and R6RS has to do with Python.
It's awfully circular to claim that Python is beautifully Pythonic despite that it's become less Pythonic even as it's adhered to its philosophy of simplicity. If anything, I'd think that a language that "reads like pseudocode!" to the uninitiated wouldn't require even casual programmers to look up syntactic elements in the documentation, the way some people talk about Python.
Wrong. It's not 1995 anymore.
Experts do things that are mystifying to a beginner.
And this is a Perl thing? What I've found from listening to beginners is that they accuse every programmer of intentionally mistifying them. OO is too hard. Macros are too hard. Monads are too hard.
Unfortunately, the experienced programmers use these features because there is a significant productivity advantage in doing so. They don't use the features to intentionally confuse beginners. The good news is that the beginners can use these features too, as soon as they are willing to admit that maybe the experts aren't actually out to subtly screw them over.
In Python, an expert would be expected to produce a solution that is comprehensible to a less-expert programmer, spanning however many lines as are necessary. It would be un-Pythonic to write code that a less expert programmer couldn't understand.
<picture of lolcat>.
Among software developers, Python programmers are of course keen to demonstrate that Python is just as awesome as other languages. That isn't really the point of Python, though. Python's value was never in how it served people who could afford to devote a lot of time to mastering it. You wouldn't judge a Prius by how fast Michael Schumacher could drive it around a track, would you?
There is a whole population of programmers out there who really don't give a damn about programming languages and who rightly don't invest a lot of time in mastering programming. They exist, they do important work, and Python's ability to serve them is important -- that's the bottom line and the truth, even if this audience isn't eager to hear it. People like that are sensitive to the difference between Ruby and Python, and they've mostly never seen decorators.
Thanks for the article! Mark
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.
If you're looking for Ruby libraries specifically, check out: http://treetop.rubyforge.org/ (Treetop uses PEGs rather than parser combinators, but like pyparsing it integrates very well with its host language.)
Treetop I had not heard of. It looks interesting.
Well the "golden oldie" equivalent in the Perl world is Parse::RecDescent (http://search.cpan.org/dist/Parse-RecDescent/).
A new kid on the block is Regexp::Grammars (http://search.cpan.org/dist/Regexp-Grammars/), which is heavily based on Perl 6 rules/grammar (http://en.wikipedia.org/wiki/Perl_6_rules).
def a(x):
def b():
print x
return b
Not sure what a prototypical ruby usecase would be.Guido's take: http://www.artima.com/weblogs/viewpost.jsp?thread=147358
Arcieri's take: http://www.unlimitednovelty.com/2009/03/indentation-sensitiv...
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' f = lambda x:(
x if (
x**2 > 10 or x**2 < 5
)
else x**3
) def some_method(x, &block)
yield x
end
then to call it:
some_method "hey" { |v| print v }
That might not look like much, but it allows you to create methods that can extend the language expressively and then use them without extra crufty syntax or sigils obstructing their meaning.I'm sure ruby is great once you're initiated, but despite >10 years of programming and having learned basic, c, pascal, lisp, java, c++, python, perl, bash, php and javascript, I have no idea what code does.
Don't mean to harsh, just an observation.
get "/hi" do |url|
print url
end
?Can anyone explain why?
task :name do |t|
# do stuff
end
I'm not sure what's the closest equivalent syntax you could create in python. with task('name') as t:
# do stuff with t
It's not really the same; the task object doesn't have control over whether the block is actually run, but sometimes it is sufficient.Python itself does varying degrees of bytecode optimisation depending on which version you're using.
def task(f):
register_task(f.__name__, f)
return f
@task
def name(t)
.....
or similar. task 'name', (t) ->
# do multiline stuffSinatra:
get '/hi' do
"Hello World!"
end
Python 2: @get('/hi')
def hello():
return "Hello World"
Python 3: def hello() -> "/hi":
return "Hello World"I have no idea what that Python 3 snippet is doing... care to share? That looks like something that's hard to Google...
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.
Fair enough. Arguing over beauty is silly anyway, I just wanted to point out that the entire thing is entirely subjective.
> The Python 3 version is using a function annotation.
Thanks, checking out PEP 3107 now. I've always seen annotations done with the @annotation syntax like the Python 2 snippet has.
The @ syntax is for decorators. Different beast altogether.
I've used decorators to add attributes to function objects in several projects in the past -- you don't have to wrap the original.
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 :)
It's unclear what "get" is. Is it a function? What does it return? My guess would be that it returns a function bound to the handler of a "/hi" url, but that's a guess.
And the block is bound to the uri given in the string, so your guess is correct.
It's also possible that one of the things in the article is the gotcha, flexible parenthesis. By convention, Rubyists tend to use parenthesis when defining functions, but not when calling them:
def get(path, opts={}, &block)
get "/hello" do
not get("hello") do
Which would still work, if you preferred. The exception to this is chaining method calls: Users.find_all_by_age(23).select {|user| user.first_name == "steve" }
... not that that's an awesome use of ActiveRecord, but whatever. 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.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?
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. 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.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.
> 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.
Why does that matter? The syntax should be clear to a capable Python developer, not someone who has never used Python.
I'm not suggesting that that particular syntax is or is not clear to said Python programmer, merely that the consideration for a Ruby programmer is useless.
get '/hi', ->
"Hello World"
You can have your cake and eat it too. >>> def print_a(inst):
... print inst.a
...
>>> class Foo(object):
... def __init__(self, a):
... self.a = a
...
>>> Foo.print_my_a = print_a
>>> f = Foo(5)
>>> f.print_my_a()
5
Not sure why my previous post was downvoted, unless maybe your definition of monkey-patching is different than mine. $ irb
irb(main):001:0> class Numeric
irb(main):002:1> def wtf
irb(main):003:2> puts "hey"
irb(main):004:2> end
irb(main):005:1> end
=> nil
irb(main):006:0> 5.wtf
hey
=> nilTo say Smalltalk IDS is a bit useless. 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.
http://blog.fogus.me/2009/03/26/baysick-a-scala-dsl-implemen...
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)It would be sillier to use Java. Or COBOL.
Definition or reference, anyone? Although I can probably guess where this is leading....
http://docs.python.org/whatsnew/2.5.html#pep-342-new-generat...
More about Python's generators here:
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 }Ruby:
def foo(bar)
if block_given?
yield bar
end
end
foo 5 { |x| puts x } # prints 5
Python: def foo(bar,fcn):
fcn(bar)
foo(5, lambda x: sys.stdout.write("%d\n" % x))
The only real difference being that the ruby code is calling a block versus a "real" function.edit Oops, had this page open for a while, didn't realize someone had replied in the interim, making my response somewhat redundant