Ruby Idioms, Part 3

January 22, 2007

Now, probably the biggest difference after the syntax, and the non-static nature of Ruby for Java heads to get used to is that Ruby is an "expressionist" language. Meaning almost all statements in Ruby evaluates to a value, i.e. everything that reasonably can be is an expression in Ruby is. This is definitely not the way Java thinks or works. So this will take some adjusting to. Don't worry I will show you an example.

Now the Java-fied Ruby code we will optimize is shown below:

    user_id = nil
    if comments
      if comments.first
        if comments.first.user
          user_id = comments.first.user.id
        end
      end
    end

Now that is some ugly code, but sometimes doing something equivalent to that in Java is very necessary. So how would a true Rubyist write that code:

  user_id = comments && comments.first && comments.first.user && comments.first.user.id

Now let us walk through what this really does:

  1. comments is evaluated, if it is =nil then the value nil is returned and the boolean expression is exited out of early because it is an AND (&&) which fails the whole expression at the first condition.

  2. We repeat the process of the previous step fo comments.first, comments.first.user, and comments.first.user.id until either nil is encountered and set as the value of the user_id variable or the final part of the boolean expression evaluates to the non-nil value that the variable value is set to.

This Ruby terseness "optimization" goes against my philosophy of producing code that reads as much like natural language as possible. For the more elegant, natural language way to solve this, refer to my previous blog entry on Rubyisms: Forwardables that discusses about how to make evaluating attributes on attributes on attributes of your given object a thing of the past in a more elegant way.