Search code examples
rubyscopeencapsulationidioms

Idiomatic ruby for temporary variables within a method


Within a method, I am using i and j as temporary variables while calculating other variables. What is an idiomatic way of getting rid of i and j once they are no longer needed? Should I use blocks for this purpose?

i = positions.first
while nucleotide_at_position(i-1) == nucleotide_at_position(i)
  raise "Assumption violated" if i == 1
  i -= 1
end
first_nucleotide_position = i
j = positions.last
while nucleotide_at_position(j+1) == nucleotide_at_position(j)
  raise "Assumption violated" if j == sequence.length
  j += 1
end
last_nucleotide_position = j

Background: I'd like to get rid of i and j once they are no longer needed so that they aren't used by any other code in the method. Gives my code less opportunity to be wrong. I don't know the name of the concept - is it "encapsulation"? The closest concepts I can think of are (warning: links to TV Tropes - do not visit while working) Chekhov'sGun or YouHaveOutlivedYourUsefulness.

Another alternative would be to put the code into their own methods, but that may detract from readability.


Solution

  • Ruby (like JS) doesn't create a new scope for each block by default (as C++, etc. do). However, in Ruby 1.9, you can try:

    last_nucleotide_position = nil
    proc { |;i, j|
      i = positions.first
      while nucleotide_at_position(i-1) == nucleotide_at_position(i)
        raise "Assumption violated" if i == 1
        i -= 1
      end
      first_nucleotide_position = i
      j = positions.last
      while nucleotide_at_position(j+1) == nucleotide_at_position(j)
        raise "Assumption violated" if j == sequence.length
        j += 1
      end
      last_nucleotide_position = j
    }.call()
    

    See How to make block local variables the default in ruby 1.9?. Any variables that you want to be used outside the block should be defined before-hand (like last_nucleotide_position).

    FM is right that a separate method may be more readable.