Ruby Idioms, Part 3

Written on 7:32:00 PM by S. Potter

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 Javafied 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, the boolean expression is exited out of (because it is all &&'s and fails at the first condition, thus the whole boolean expression fails) and nil, which was the last value evaluated in that expression is set to user_id. This is the same outcome that would have occurred in the first code snippet.
  2. We repeat the process of the previous step for comments.first, comments.first.user and finally comments.first.user.id until either nil is encountered and set as the value of user_id or the final part of the boolean expression evaluates to a non-nil value and that value is set to the value of user_id.
Do you follow? If not, reread through things again, because it should eventually make sense after a while. So this Ruby "optimization" goes against my philosophy of producing code that reads as much like natural language as possible. For the better more elegant, natural way to solve this, refer to my previous blog entry on Rubyisms: Forwardables, which talks about how to make evaluating attributes on attributes on attributes of your given object a thing of the past in a more elegant way. This isn't, however, an idiom, since it is not a specific construct of the Ruby language that provides this utility.

If you enjoyed this post Subscribe to our feed

3 Comments

  1. ed |

    hi,

    do you know about method "defined?" ?

    user_id = comments.first.user.id if defined? comments.first.user

    the method defined? returns nil if
    its argument is not defined

    The defined? operator returns nil if its argument (which can be an arbitrary expression)
    is not defined; otherwise it returns a description of that argument. If the argument
    is yield, defined? returns the string “yield” if a code block is associated with the
    current context.
    defined? 1 # => "expression"
    defined? dummy # => nil
    defined? printf # => "method"
    defined? String # => "constant"
    defined? $_ # => "globalvariable"
    defined? Math::PI # => "constant"
    defined? a = 1 # => "assignment"
    defined? 42.abs # => "method"

     
  2. S. Potter |

    Hi Ed,

    Yes, of course I know defined?. I am glad you brought this up.

    defined? is used in a different problem context to the context of the problem I use in this blog entry. It is a way to determine the type of object passed in rather than determining its value.

    In the problem scenario in this blog entry we wish to determine whether it is nil or not.

    I understand the approach you are suggesting to aid in the solution of this problem, however I do not find it more readable than the short-cut idiom that I propose, even though the it is not that elegant. I am not a fan of using defined? except for what it is intended for. Also the defined? solution would be slightly less terse, in addition to less readable (in my opinion). The vocabulary (i.e. "defined") is more codish than natural. That is my personal persuasion though. Others, I am sure, will have different opinions on this.

    So, thanks for suggesting an alternative for other Ruby developers that may not object to using defined? in a solution to this problem.

    SP

     
  3. S. Potter |

    I should correct myself. The "defined?" approach may or may not be terser. It depends on mostly the length of variable names and number of constituents, for the purely terse inclined (not me).

     

Post a Comment