Ruby Idioms, Part 2

January 22, 2007

Now the "idiom" we will use is not specific to Ruby, since I am pretty sure Perl has one of the constructs we will use to solve the stated problem, but it is still idiomatic, since the majority of popular OO languages (static, dynamic or otherwise) do not have it (as far as I know). Also some consider this to be a sub-optimal idiom, because there is a terser way to do something like this. However, the idiom I recommend below is much more multi-purpose, though I will show the terser version for the trivial case.

Firstly our Javafied Ruby code looks like the following for the problem at hand:

    if not var
      var = "some text string"
    end
    # OR for a pure Java to Ruby translation with ZERO Rubification
    if nil == var # of course "if var == nil" is equivalent too.
      var = "some text string"
    end

Now this is the most trivial case of wanting to set a variable to a value only when it is nil. The Ruby idiom I advocate is much more versatile than for this trivial case, but there is an even terser Ruby idiom that is only applicable to this case, which I wanted to show you first:

    var ||= "some text string"

As you can see this is very terse, but my question is, is it readable? Well to many Rubyists it is, but this relies on expressionistic understanding of how Ruby works under the covers. On projects involving developers with varied skill levels, I would definitely prefer my proposal below.

Now onto the more readable and more multi-purpose idiom that reads much more like my natural language (which is my preference in general):

    var = "some text string" unless var

Now some of you may think this isn't as readable as it could be, I concur. I sometimes prefer to use something like the following, but consistency on a project is important in my view, so pick on and go with it:

    var = "some text string" if var.nil?

I do find myself using the terser "or equals" idiom in favor of the above for the trivial case (but consistently on projects with other advanced Ruby developers). The "if var nil?" idiom can be used in more multi-purpose situations, not only when you wish to set a variable when it has a nil value (that is null to you Java heads).

A non-trivial usage of the "unless" version of the idiom would be well suited to a code snippet that tries to do the following:

    user_defined_fruits = ['apple', 'cantaloupe']
    fruits = ['apple', 'banana']
    user_defined_fruits.each do |fruit|
      if fruits.include? fruit
        fruits << fruit
      end
    end
    fruits #=> ['apple', 'banana', 'cantaloupe'] NOT ['apple', 'banana', 'apple', 'cantaloupe']

Now a better way of doing this with the "unless" version of the idiom would be:

    user_defined_fruits = ['apple', 'cantaloupe']
    fruits = ['apple', 'banana']
    user_defined_fruits.each do |fruit|
      fruits << fruit unless fruits.include? fruit
    end

As you see above the code is terser, while being as readable, if not more (in my opinion again).

Again the as-terse-as-possible enthusiasts will love the following:

    user_defined_fruits = ['apple', 'cantaloupe']
    fruits = ['apple', 'banana']
    fruits |= user_defined_fruits