My Thoughts on Python vs. Ruby

I’ve been using Python at work for the past few months.  I learned Python back in the early 2000s, but never used it for any large projects.  I learned Ruby in late 2005, and it quickly became my language of choice for most cases.

So while I still prefer Ruby, and will likely use Ruby more in the future than Python, I wanted to assess the strengths and weaknesses of Python in relation to Ruby.  Perhaps some of the lessons could be applied when writing Ruby, and it could help to decide when to use each.  Also, I’m interested in programming language design, and wanted to document pros and cons in that light.

Where Python Sucks (As Compared to Ruby)

  • Have to explicitly include self in EVERY method declaration.
    • Including @classmethod declarations (although people usually use the name cls instead of self there).
    • Except @staticmethod declarations.
  • Have to use self everywhere to reference an object’s own attributes.
  • Inconsistency of things like the len() function, when everything else is a method.
  • Inconsistency of having some built-in classes with lower-case names.
    • And they’re not whole words, so you have to memorize them: list, dict, str, int.
    • Even more bizarre is dict vs. OrderedDict.
  • I’m not a fan of True and False being uppercase.
    • I’m a bit less concerned about None, for some reason.
    • If they’re going to be uppercase, they might as well be all caps, in my opinion.
  • Inconsistency of camelCase versus snake_case in some modules.
  • Claims to prefer explicit over implicit, yet does not use new to create an object.
    • It is nicely concise, but makes it look too much like a regular function call.
  • The implementation of lambdas is too limited.
    • Makes using map function not very useful.
  • Class methods are less than ideal to implement.
    • Probably better to use functions within a module instead, in many cases.
  • Lack of good functional programming tools makes it harder to manipulate lists.
    • Have to often resort to creating an initial list and adding to it in a for loop.
  • I don’t understand why r’regex_string’ doesn’t just create an actual regular expression object.
  • I miss Ruby’s method-call-or-property-getter syntax.
    • Nice that I can get it by adding @property to method definitions, but that’s a bit messy.
  • I don’t understand why lists don’t have a join() method; it seems backwards to call join on the string used to connect the list elements.
  • I miss unless; seems like with all the keywords, Python would have added that.
  • I really miss ||= to memoize.
    • The distinction between unset variables and variables set to None makes it hard.
    • I also miss +=.
  • I really miss statement modifiers (if or unless at the end of the statement/expression instead of the beginning).
  • I miss being able to assign to a compound statement (x = if True: 1; else: 2).
    • While Python does allow this simple case, it does not allow more complex cases.
  • The way modules, files, and classes work, I either have a lot of classes in one file, or have to come up with more module names in order to split classes into different files.
  • The preference for bare functions within modules over class methods often leads to functions outside of classes, when they’d make more sense more closely associated with the class.
  • I don’t quite understand the necessity for pass.
    • Seems like allowing 0 lines of indented code would suffice instead.
  • I miss implicit return.
    • Explicit return looks a bit nicer, but is less concise, and I’ve gotten out of the habit.
  • Mixins turn out to be more useful than multiple inheritance.
  • I miss string interpolation.
  • I really miss Array#first and Array#last.
  • I really don’t like that 0 is falsey.
    • I could live with empty lists and dicts being false, but not 0.0 and 0.
  • Comparing a string to a regular expression seems harder than it should be.
  • Converting to a Boolean is not as easy a Ruby’s !! syntax.
    • OK, bool(expression) isn’t so bad, I guess.

Where Python Rocks

  • Indentation removes the need for end everywhere.
  • Import statements are nice.
    • Can import everything, or just a few things.
  • Annotations are nice for aspect-oriented modification of methods.
    • Does it make it hard to debug though, like alias_method_chain in Ruby?
    • It’s kind of tricky to write them though, due to doubly-nested function definitions.
  • List comprehensions are more powerful than map.
    • But map can be more concise for the most common cases.
  • Can add arbitrary attributes to any object, class, or module.
  • The object creation syntax is nicely concise.
  • Sometimes the ability to add a bare function within a module is nice.
  • Keyword arguments are nicely done.
    • Ruby’s emulation via hashes without braces is OK, but the corner cases are problematic.
  • Docstrings as part of the language is nice.
  • The new with keyword looks like a halfway-decent replacement for blocks.
    • Seems like a lot more work that using blocks and yield though.
  • Python 3 drops support for octal literals starting with a 0.
    • Still allows it via a 0o prefix.
  • No support for all the crazy Perl-inspired globals.
  • The names list and dictionary are better than array and hash.
    • The Ruby names are more about the implementation, especially hash.
    • I’d much prefer the name map over hash, or even dictionary.
    • The name list is only slightly better than array.
  • List and string slicing is quite nice.
    • I do wish that the syntax was “..” instead of “:” though.
    • Slice assignment is even cooler.
  • I prefer the Python dict syntax over the Ruby hash syntax (“:” vs. “=>”).
    • The Ruby 1.9 symbol hash syntax is an improvement, but not quite as good.
  • Checking for string containment is nice: if substring in string.

Where Ruby Rocks

  • Consistency.
  • Blocks.
  • Excellent functional tools to deal with Enumerable.
  • Meta-programming.
  • Optional parentheses.
  • Modules and classes are also objects.

 

Debugging Pattern – Grenade

I’ve been more interested in programming patterns lately, partly due to the Ruby community’s recent interest — especially the Ruby Rogue podcast’s love affair with “Smalltalk Best Practice Patterns”.

I consider most of the patterns in “Smalltalk Best Practice Patterns” to be patterns “in the small” — things that are typically employed on a single line or method. The Gang Of Four patterns are more medium sized, dealing with methods and classes. The PEAA book covers architectural-scale patterns. I suppose “The Pragmatic Programmer” and similar books could (should!) be considered to be very general patterns, mostly about the practice of programming.

One type of pattern that I have not seen discussed much is debugging patterns. I’m not exactly sure why that is; probably just our general concentration on designing the program code itself. There are definitely testing patterns. But I can’t think of anything that I’ve seen that covers debugging patterns. A quick search on the Internet doesn’t turn up too much.

Anyway, a co-worker (Helena) and I were debugging recently, and were having trouble figuring out where a certain method on a certain object was being called. We came up with a really cool solution. We immediately called it a grenade, because its entire purpose is to blow up (raise an exception) and display a backtrace to show us the caller of the method that we’re looking for.

Here’s our implementation in Ruby:


module Grenade
  def method_under_investigation(*)
    raise "method_under_investigation called"
  end
end

class Xyz
  ...
  def xyz
    object_under_investigation.extend(Grenade)
  end
  ...
end

I’m sure we could wrap that in some more semantic sugar, even going as far as making it look something like this:


class Xyz
  ...
  def xyz
    object_under_investigation.blow_up_when_method_called(:method_under_investigation)
  end
  ...
end

I’m not sure that would really be worth it though, unless we were to add it to some sort of library.

So that’s our contribution to the (small) list of debugging patterns.