Ruby vs Python

Python vs Ruby

Python vs Ruby

Ruby and Python are similar programming languages in that they use much of the same syntax, runtime speed, they both come with large standard libraries to do most common tasks, and are generally suited to solving similar kinds of problems. However, people often strongly prefer one language over the other. Personally, I prefer writing in Ruby. Here I’ll highlight some of the differences between the languages that I think are important.

What are blocks?

One of the great features I like about the Ruby language is “blocks”. Ruby provides convenient syntax for passing a block of code to function/method. The block can take zero or more arguments and do stuff with them. There are two syntaxes for Ruby function/method call with a block; do/end is the same as {}.

func do |arg1|
  # do stuff with arg1 ...
end
func{|arg1| # do stuff with arg1 ... }

The yield statement can be used to call the block when writing a function/method that takes a block.

def func
  # set-up code
  yield "some value"
  # clean-up code
end

The ability to easily treat blocks of code as a first class thing in the language gives a huge amount of power. In many of the places Ruby uses blocks, Python introduces new syntax to the language. For example, for loops, with statements and list comprehensions.

Blocks: iterators

To loop over each item in an array/list in Ruby, we use the each method and pass it the block of code we want to be executed for each item. In Python, we instead use a for loop. It is part of the language that utilises the iterator protocol defined on the array/list to loop over each item.

Ruby each call with a block on an Array:

items = [1,2,3,4]
items.each do |i|
  puts i
end

Python for loop on a List:

items = [1,2,3,4]
for i in items:
  print(i)

Blocks: “with” statement

We want to run some code that has some standard set-up to be run before our code, or some standard clean-up to be run after our code, such automatically closing a file after we have finished using it. In Ruby we can use blocks; we pass File.open a block of code that we want to run with the file open and it automatically closes the file after the block has finished. In Python, we can do something similar via the with statement.

Ruby File.open block:

File.open('somefile.txt') do |f|
  puts f.readline
end

Python with statement:

with open('somefile.txt') as f:
  print(f.readline())

Blocks: manipulating arrays/lists

In Ruby we can pass blocks to map to apply an operation on each item and return a new array/list. Here we are adding 1 to each item:

items = [1,2,3,4]
newitems = items.map{|i| i + 1 }

Python introduces the syntax for “list comprehensions” within square brackets:

items = [1,2,3,4]
newitems = [i + 1 for i in items]

If we want to only select items that are divisible by 2 and then add 1 to we can do…
Ruby:

newitems = items.select{|i| i % 2 == 0 }.map{|i| i + 1 }

Python:

newitems = [i + 1 for i in items if i % 2 == 0]

How about the other way round?
Ruby:

newitems = items.map{|i| i + 1 }.select{|i| i % 2 == 0 }

Python:

newitems = [i for i in [i + 1 for i in items] if i % 2 == 0]

We now have nested list comprehensions in Python, I find it much harder to follow.

Blocks: Sorting by attributes

Say we want to sort an array by a attribute in a Hash/Dict. In Ruby, we can pass a block telling sort_by to use the “width” attribute for each item:

items=[{length: 2, width: 3},{length: 3, width: 4},{length: 4, width: 2}]
sorted_items = items.sort_by{|item| item[:width] }

And the result we get is:

[{:length=>4, :width=>2}, {:length=>2, :width=>3}, {:length=>3, :width=>4}]

In Python we can use itemgetter from the operator module to tell sorted to use the “width” attribute:

items=[{'length':2,'width':3},{'length':3,'width':4},{'length':4,'width':2}]
import operator
sorted_items = sorted(items, key=operator.itemgetter('width'))

The Python example doesn’t exactly seem obvious to me and a more generic way to sort by any expression in Python is to use the lambda syntax. It’s a bit like a block in Ruby:

sorted_items = sorted(items, key=lambda item: item['width'])

Built in functions

Python has lots of functions built into the language that are used to do common operations, such as return the length of an array/list, or to reverse its order. This means that as well as knowing the name of the function to do this, we also need to know if we need to invoke it via len(list) or list.len(). I also think this is confusing for new people learning Python as to why, for example, split is invoked differently from len, plus the documentation for methods/function may be in either the “Built-in Functions” section, or the “Lists” section.

In Ruby, we start reading this from the left with the String object sentence, on which we call split to split on whitespace and return an Array object, on which we call length to return the number of items in the Array.

sentence = 'a short sentence'
sentence.split.length

In Python we start on the middle with the String object sentance, on which we call split to split on whitespace and return a List object, which we then pass as an argument to len which returns the number of items in the List.

sentence = 'a short sentence'
len(sentence.split())

The Ruby approach typically combines more readably from left to right; for example, if we split the sentence string, reverse it, capitalise the first letter and join it back together we’d do something like…
Ruby:

sentence.split.reverse.map{|word| word.capitalize }.join(' ')

Python:

' '.join([word.capitalize() for word in reversed(sentence.split())])

It takes me a while to work out where to start reading the Python line. I certainly don’t want to think about doing anything with ' ' to start with, as I’ll have forgotten about it when I’ve worked out what all the rest is doing.

() to call methods/functions

The argument for keeping () is to know when it’s a function/method call or when it’s just referencing a variable. In Ruby this situation doesn’t occur because it’s always a method call, so we don’t need to think about it. If we want the member variables of a class to be public, that’s easy: we can use attr_accessor to define “boiler plate” getter and setter methods.

Non Issues

Often one the most debated, but I think largely irrelevant issues, is the significance of whitespace. Python has a colon and syntactically significant whitespace, and Ruby has lines with end on. I think pattern recognition is the key here. If we’re used to seeing end closing off sections of code, it looks initially looks strange if it’s omitted, but most people could easily adapt to recognise either pattern with ease. I think the Ruby programmers’ willingness to use CoffeeScript to generate JavaScript, which does have syntactically significant whitespace, shows this is not really an issue.

Ruby:

def inc(n)
  n + 1
end

Python:

def inc(n):
  return n + 1

Same for @ vs self. when referencing class member variables. The Ruby code uses less characters so probably has the advantage.
Ruby:

class MyClass
  def initialize
    @n = 0
  end
end

Python:

class MyClass:
  def __init__(self):
    self.n = 0

Closing Remarks

Ruby vs Python is an ongoing debate. Lots of people prefer Ruby and lots of people prefer Python. There are many other differences between the languages, but I think the things covered here are the main things I see people using in these languages, and the things that I think newbie scripters often come across.

One of the great things about a programming language based around blocks, is that once you understand blocks, you can stop worrying about the language itself and start focussing on how to solve your problems. In Python, if you want to go a stage further and write code that allows the language features discussed above to be used on you own objects (instead of using them from libraries), you also need to know the “initialiser protocol”, “generator” syntax, with statement “context managers”, etc.

However, when choosing which language to use, it often better to use the language that the community you want to work with is using. For example, if you want to do scientific computation you’re probably more likely to find a community and some tried and tested libraries in Python. If you want to connect to the latest NoSQL database, you’re probably more likely to find a community and some tried and tested libraries in Ruby. The ability to easily work with existing libraries, or a community, is typically much more important than syntax and semantics of two similar languages like these.

Update: This post has made it onto Reddit: Reddit Python commentsReddit Programming comments

Update: Following on from the many comments about Python having one way to do things, I’ve written an article on why I didn’t think that was worth including. senktec.com/2013/09/one-way-to-do-it

If you enjoyed this post, consider leaving a comment or subscribing to the RSS feed.
  • ejo

    Nice article. I am enjoying ruby programming.

  • Victor

    All your complaints about Python’s syntax are due to the fact that you are not experienced in it.

  • http://znasibov.info/ Zaur Nasibov

    Totally agree with Victor. Moreover you are forgetting about the issues in Ruby! There are no unambiguities with Python’s `len()`. How about both `.size` and `.length`in collections?

  • bastibe

    I would say that Ruby blocks are just some syntactic sugar for passing a
    function or lambda as an argument. While this is no doubt a cool
    feature, it is not functionally different from Python.

  • pcdinh

    In your review, Ruby syntax is not nicer than Python’ s one. Moreover Python library and ecosystem is much much bigger than in Ruby, making Python an obvious choice in every new project at the moment

  • http://klen.github.com Kirill Klenov

    Ruby looks pretty nice. Thanks.

  • Andrey Shipilov

    You just seem to be not experienced in Python and that’s all…
    Also — “The Ruby code uses less characters so probably has the advantage”. Yes, @ is shorter, but what happened with “end end”?
    Anyways, very biased article with poor examples.

  • sigzero

    “The Ruby code uses less characters so probably has the advantage.” Say what?!?

    By the way, almost to the example, the Python is more readable.

  • http://bitrot.io/ryan Ryan Macy

    You’re using list comp’s when you should be using filter & map.

  • http://bitrot.io/ryan Ryan Macy

    filter(lambda n: n % 2 == 0, map(lambda n: n+1, items)) seems more readable to me, than the overuse of list comps.

    I agree with the above.

  • Guest

    > Moreover you are forgetting about the issues in Ruby!

    Like?

    > How about both `.size` and `.length`in collections?

    What do you say about “join” ? The OP has only said Ruby’s syntax is easier and I agree with him. He never told Python is inferior. Please don’t blindly reply with dismissive comments like Victor did.

  • dreucifer

    The nested list comprehension example is non-Pythonic. Instead of `[i for i in [i + 1 for i in items] if i % 2 == 0]` you would use `[i+1 for i in items if (i + 1) % 2 == 0]`.

  • Stephen Tanner

    Instead of:
    items = [1,2,3,4,5,6,7,8,9]
    [i for i in [i + 1 for i in items] if i % 2 == 0]

    You could easily use:

    [i + 1 for i in items if (i+1) % 2 == 0]

    Which is by far easier to read than:
    items.map{|i| i + 1 }.select{|i| i % 2 == 0 }

  • George

    Nitpick:

    `newitems = [i for i in [i + 1 for i in items] if i % 2 == 0]` is iterating over the items twice, which is ugly (as you noted) and unnecessary.

    You can change it to:
    `newitems = [i for i in (i + 1 for i in items) if i % 2 == 0] # Generator`

    …Or better yet:
    `newitems = [i + 1 for i in items if i % 2 != 0]`

  • http://www.senktec.com/ Stefan Senk

    Does your example not support my argument that an ‘anonymous function’ or ‘block’ based approach is preferable to a list comprehension?

  • http://www.senktec.com/ Stefan Senk

    My point was that regardless of programming preferences, you should not decide that one language is always the right choice for every project.

  • http://www.senktec.com/ Stefan Senk

    In Python you have to define the function with a name and then pass it via the name, unless it’s small enough to use Python’s lambda. I believe passing anonymous functions direct does make a big difference and is more than just a ‘cool feature’.

  • http://www.senktec.com/ Stefan Senk

    Agree that your example is neater than the nested comprehensions, but the ‘i + 1′ logic is duplicated. I think duplicate code should be removed whenever possible.

  • http://www.senktec.com/ Stefan Senk

    Agree that your example is better than the nested comprehensions. If you can easily change the if statement (or select in Ruby) so it can run first that’s great.

  • http://www.senktec.com/ Stefan Senk

    Perhaps the Pythonists can confirm which is preferred out of list comprehensions and map/filter? I was under the impression that Guido would ideally have liked to remove map/filter in favour of list comprehensions as the one true Pythonic way to do things?

  • panzi

    Python decided to keep the interface of list small, which is a good thing. It means that it’s easy to write a list like class that you then can use wherever a list is expected. So Python pulled some things out of the list class into builtin functions (map, filter, zip, sorted, enumerate, min, max, sum, all, any, itertools.* etc.) or put them into different classes (string.join).

    Things where Python is better than Ruby:

    Ambiguity. Like mentioned in Ruby there are often many aliases for the same method, which makes code of different people confusing to read.

    Generators. With this you can do lazy evaluation in Python. Ruby’s lazy lists aren’t really comparable (though good enough most of the time).

    Unicode/Encodings. Ruby nonsensically attaches an encoding to it’s strings (that are otherwise basically byte arrays). This sometimes makes string operations a pain. I had the case that deserializing of different YAML objects gave me strings with different encodings (they where all generated with an older version of Ruby), and then ERB crashed when it tried to concatenate strings with different encodings. In Python 3 there is str (unicode in Python 2) and bytes (str in Python 2 – yes that was a bumpy transition). If you want to do something with strings (text) you use str. It’s more or less abstract unicode. There are no encodings. Encodings are used to *encode* or *decode* a string (when you write or read it to/from a file etc.). In memory you have text and don’t have to care about anything else (e.g. you don’t have to care about whether you DB driver returns utf8 strings, iso-8859-1 strings or binary strings – which IMHO wrongly are called ASCII-8BIT in Ruby). In Python, the bytes (and bytearray) class(es) are used to manipulate binary data. There is a clear distinction. This is for me the biggest WTF in Ruby.

    Mutability of strings. In a dynamic language (and languages at the level of e.g. Java) strings should IMHO be immutable. Why? Because when you pass a string to some method it is not clear what it does. Does it copy the string or “take ownership” and manipulate it, so that the caller has to make a copy before it passes the string to the method? String manipulations with immutable strings can still be fast (join/StringBuilder/StringIO). In other languages one can do more sophisticated things like copy-on-write strings (QString in C++) or making the ownership clear in the API (Rust).

    Symbols and strings. In Python there are only strings, but in Ruby there are also symbols. Wait, did this API want the keys as strings or as symbols? What happens if I pass a Hash with mixed keys? Completely confusing! Rails actually invented a HashWithIndifferentAccess (actual class name) because of this. Also what some APIs return changed between Ruby 1.8 and 1.9! A minor release! (At least judging from the version numbers.)

    Builtin types cannot be monkey patched in Python. Some say this is an disadvantage, I think it prevents a lot of mess (compare prototype.js). You can derive them and monkey patch the derived classes.

    And personally I like to define ranges/slices by [start,end) much better than by start+length.

  • http://hackery.io/ Ryan Macy

    Yeah but there are certain benefits to having to name it, which is why python forces a terse lambda format.

    def has_remainder: n % 2 == 0

    Which is still one line that becomes testable, exportable, and reusable.

  • http://hackery.io/ Ryan Macy

    When you’re nesting comprehensions with predicate logic and mutation, then sure.

  • http://hackery.io/ Ryan Macy

    I’m talking in the context of the example you provided. Comprehensions are preferred when they aren’t nested. When you end up with something like your example it would be pythonic to just expand them as for .. in block iterations for readability and maintainability. What are you gaining by squashing all of that logic together? It’s not going to run much (or at all?) faster. It’s just harder to read and will slow someone new to the language down.

    Even then, there are optimisations others have pointed out. Like using a generator instead of a list comp inside of a list comp, which will lazily evaluate.

  • zzz

    Python smashes Ruby in every way.

  • lanzz

    None of your examples demonstrate any better suitability of one language over the other in a specific situation. You’re mostly pointing matters of style and personal preference. If your point was that one language isn’t always the right choice, you have missed it.

  • lanzz

    In Ruby you don’t seem to be able to refer to your block within the function that has been passed the block, or at least you’re not demonstrating such possibility — you’re only allowed to call it using “yield”, as the block does not have a name by which to be referred to within the function. So basically, you cannot pass the block to another function, you’re stuck with yielding it within that exact function that has been passed the block.

    This makes blocks VERY different from “first class things”, as you call them. “First class” is generally defined as “an entity that can be constructed at run-time, passed as a parameter, returned from a subroutine, or assigned into a variable” [Wikipedia definition of "First-class citizen"]. You haven’t demonstrated the ability to use a block in any of these scenarios.

    Python’s lambda expressions, on the other hand, are truly first-class. You can pass them around as values, invoke them wherever you wish, and generally regard them as indistinguishable from true functions. The single-expression limitation is actually a design decision of the language, not an inherent shortcoming of the construct.

  • George

    Really? More readable than [n + 1 for n in items if n % 2 == 1]?

  • laurencerowe

    I’d recommend using a generator expression (basically a lazy list comprehension) instead for the inner part:

    items_plus_one = (i + 1 for i in items)
    filtered_items = [i for i in items_plus_one if i %2 == 0]

    (This particular example could simply be rewritten as [i + 1 for i in items if i % 2 != 0])

  • laurencerowe

    It’s generally unnecessary to pass a list comprehension to a function, instead use a generator expression instead:

    ‘ ‘.join(word.capitalize() for word in reversed(sentence.split()))

  • http://www.senktec.com/ Stefan Senk

    I think you want an example that does something like this. func1 takes a block and passes it as an argument to func2 which then calls it …

    def func1(&block)
    func2(block)
    end
    def func2(block)
    block.call
    end
    func1{ puts ‘My Block’ }

    Ruby also has lambdas, which don’t have the single-expression limit. Presumably you’ll consider that undesirable, but I think it’s great.

  • http://www.senktec.com/ Stefan Senk

    Ok, totally except that’s an improvement over my example.

    Do people really like the way this is written starting with the space character, though?

  • Foxious

    It’s not just .join. What you’re missing is that you can call member functions on any object literal.

  • Nick Brown

    I can’t help but notice a theme between the two camps that reflects the differing core philosophies.

    Ruby’s philosophy is many ways to accomplish a goal.

    Python’s is “there should be One True Way” to accomplish a goal – one solution that is better than the rest.

    The Ruby supporters here don’t seem to mind people preferring Python at all. Python devs have found a way they prefer to solve the problem. Cool.

    The Python supporters here definitely seem to feel the need to argue that their language is the One True Way, and other languages are inferior.

  • http://www.senktec.com/ Stefan Senk

    Most of the traffic here over the last week has come from Reddit and, as it was linked from the Python section, it’s understandable that Python devs would want to defend their language. However, I think you do make an interesting observation.

  • Frikkie

    It is interesting to note that the ruby community doesn’t have a term like “pythonic”. While I prefer python ( I think it is elegant and well defined ), I have found that both Python and Ruby users get overly religious about their language choices. While purists are having their debates, the rest of us are rolling out software, making the world a better place, or at least making some cash.

  • http://www.senktec.com/ Stefan Senk

    I think the Ruby community would use something like “idiomatic Ruby code” to mean the equivalent of “pythonic”.

  • Steven Chartis

    “The Ruby code uses less characters so probably has the advantage.”

    Using this logic Perl is the better language. ;D
    But really, I find Python’s use of self. to be a lot easier to read. And I personally think that Python’s implementation is just as fast, if not faster to type.
    Also, I’m really not too fond of Ruby’s
    w
    ….a
    ……..v
    …………e
    ……..end
    ……..s
    ….end
    end
    Definitely preferring Python’s
    str:
    ….uct:
    ……..ered
    ….fl:
    ……..ow

  • Rabcor

    These languages look strikingly similar, i’ve heard of Ruby programmers embracing Python like a godsend though.

    I use python, but i honestly don’t see a reason to dislike Ruby, i’ll prefer Python for one very simple reason though.

    Smaller line count.

  • Taylor Marks

    “Same for @ vs self. when referencing class member variables. The Ruby code uses less characters so probably has the advantage.” – I lol’d at this. In nearly every example (including this one), the Python code had fewer lines and fewer characters involved to do the same thing. Further, @ requires hitting the shift key and using your left hand to hit something on the number row, whereas self. is 3/5th on the home row, with the other two keys being just one line below or above the home row. I’m not saying that self. doesn’t take longer to type, just that you may be surprised at how little of a typing advantage switching from self. to @ yields.

    Ruby seems to strongly resemble SmallTalk… perhaps even more strongly so than Obj-C does (which is interesting, since Obj-C is generally considered the child of SmallTalk mated with C.)

    My biggest issue with Python doesn’t seem like it’s resolved by Ruby: it’s often confusing what needs to be passed in to each argument.

  • http://www.senktec.com/ Stefan Senk

    So I think you agree @ vs self should be in the “non issues” section?

    Regarding function arguments, do keyword arguments in Python, or hash arguments Ruby, help?

  • Taylor Marks

    I’m not familiar enough with Ruby to say anything about hash arguments (that name sounds intriguing…) – I have perhaps 3 hours total of Ruby experience, versus ~1K hours of Python experience – but keyword arguments are a slight improvement over positional arguments. Not as much as you might think, though. The most common issue with passing incorrect arguments is where it’s not clear if a function wants a Thing passed in or a List of Things passed in. One could blame the person who wrote the function for not making it capable of accepting either, or for not making it clearer, but I blame the language for this problem. I never have that problem in a language like C, C++, Obj-C, or Java, because those languages all require the types of the arguments to be part of the declaration.

    I’m planning on creating my own programming language in a few months after graduate this April… I’ve been drafting up ideas for how I could dramatically improve function declaration so that a huge amount of bugs could be detected at compile-time (IE, you could include in the declaration that an argument must be within a range and that it will return a value within a range, and at compile time your code would be analyzed to determine whether these statements are true. Similarly, with strings, you could say that arguments must match a regex pattern and that strings returned will match a different pattern.)

  • Karl Coelho

    I’m 14 and I know Ruby. Python is utterly horrible for a beginner. I say this with evidence from my own friends. Don’t go with Python. Ruby is definitely the way.

  • Michael

    newitems = [i for i in [i + 1 for i in items] if i % 2 == 0]

    Geebus! Why the second listcomp? One will do just fine.

    newitems = [i+1 for i in items if i % 2 != 0]

  • Nir

    Respectfully, the “one way to do it” is one of the most important aspects of Python. The real fundamental difference between Ruby and Python is that: Python encourages you to hook into existing structures to do things, while Ruby encourages you to create your own structures. I didn’t come up with this by the way, I saw it in a talk after reading a lot of Python vs Ruby articles, and I realized the guy really nailed it.

    The end result: In Ruby, it’s much easier to create DSL’s and in general create very specific ways of doing things to a particular problem domain. Python makes this harder, but the enforcement of doing things a particular way makes Python one of the easiest languages to read, in real code, as opposed to contrived two line examples. Ruby, people tend to get clever and do things that may be nicer once you appreciate them, but are harder to read.

    More time is spent reading code than writing it. Python is as close to executable pseudo-code as it gets. This is the biggest advantage of Python.

    I should add: the ‘real’ difference if we’re willing to admit non-fundamentals is that Python has for more libraries and realms of application than Ruby.

  • http://www.senktec.com/ Stefan Senk

    As I discussed in more detail in a follow up article, I don’t believe that Python delivers as close to “one way to do it” as people claim it does, and I also don’t think it’s an ideal worth pursuing. http://www.senktec.com/2013/09/one-way-to-do-it/

    While most examples are probably contrived to some extent, I believe it’s more useful to try and put down some code examples, rather than referring to some hypothetical “real code”.

  • Nir

    It’s more useful to look at contrived code snippets, than to listen to what the strong majority of people who have programmed in Python are telling you?

    Even by the standards of contrived code, these are… pretty contrived. In your first example, two of them are both exactly list comprehensions, it’s just that in one you defined an intermediate function. Any programming language with functions has an infinite number of ways to do things, by this measure. Most of the other examples, there are very good and specific reasons why the two ways exist, often related to generality. As opposed to someone just deciding that unless is clearer than if not.

    But these small scope syntax examples don’t really have that much to do with it. Here’s a real example: Python heavily pushes you hooking into the language using the __functions__. In Python, people use for loops, and the only way to use a custom class with a for loop is to define __iter__. In Python, people use ‘in’ to check membership, and again you have to define __contains__. You don’t ‘have to’ but this is what idiomatic Python looks like. In Ruby, there isn’t really anything to hook into. You could give your collection a method each. But you don’t have to. You could call it whatever, and the code would like identical post refactoring. Not true in Python! There’s no way to use the built in for loop directly, short of defining that method.

    There is no way to force people to do it, nobody is claiming that. But the language, documentation, and community all push you heavily in that direction. To counter your stack exchange example, here’s one of my own: check out looping through an array while needing the index. There are dozens of examples of people told not to do for i in range(len(vector)), but instead use the enumerate function.

    As for whether it’s worth pursuing, I strongly disagree. As I said, more time is spent reading than writing code. In Python, if you give two reasonable programmers the same task, the result will be far more similar than if given to two Ruby programmers. This also means, pretty directly I would argue, that the two Python programmers would understand each other’s code more easily.

  • http://www.senktec.com/ Stefan Senk

    I think it’s interesting when the pursuit of a particular goal, such as readability, can lead people to opposing viewpoints. The Python programmer’s view being that there should be one obvious way to do it, so the code will always be written in the same way, and is therefore clear to others reading it. The Ruby programmers view being that we should allow different ways to write the code, so the code can be written in a way that best emphasises the meaning behind it, and is therefore clear to others reading it.

  • Nir

    I agree that that sounds equally nice, in theory. The creator of Perl said something very similar. Perl is now regarded by most people as a terribly difficult language to read. Python and Ruby are both flexible enough to solve real world problems in a natural way, so both can easily emphasize meaning. The main exception to this, as I said, is that Ruby offers more flexibility and better syntax in defining your own control structures, which is why it’s better for DSL’s.

    I think the DSL/flexibility vs readability/simplicity trade-off just hits the nail on the head. I wish I had the link to the talk, to send to you. But there are plenty of Pythonistas who think that Python can do anything that blocks can do, just as easily. So if they can have their illusions, I guess your entitled to believing that Ruby is just as readable as Python.

This site uses cookies. Find out more about cookies.