Reputation: 81570
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.
Upvotes: 3
Views: 1866
Reputation: 196
If all you want is to keep new variables from spilling out into the rest of your program, you can wrap your code in a block using 1.times
. Any new variables you create inside the block will be destroyed when you close the block. Just keep in mind that any changes you make to pre-existing variables will remain once the block closes.
y = 20
1.times do
# put your code in here
i = 1
puts x = y # => 20, because y is available from outside the block
y = 'new value' # We can change the value of y but our changes will
# propagate to outside the block since y was defined before we opened
# the block.
end
defined? i # => nil, i is lost when you close the block
defined? x # => nil, x is also local to the block
puts y # => 'new value'
Upvotes: 1
Reputation: 29915
You are looking for the Ruby equivalent of Lisp's let
special operator. Ruby does not support it out of the box but you can hack it in very easily, and the resulting syntax is like this:
x = 10
scope { |x|
x = 30
}
puts x #=> 10
see: http://banisterfiend.wordpress.com/2010/01/07/controlling-object-scope-in-ruby-1-9/
Upvotes: 1
Reputation: 284927
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.
Upvotes: 2
Reputation: 42421
I think the term you are looking for is variable scope -- in other words, you are looking for ways to confine the scope of i
and j
. But you don't need to worry about that. The problem at hand calls for creating separate methods -- regardless of scope considerations.
This will improve readability, because it will allow the reader to grok the code starting at the high level and then boring in deeper only as needed. It will also improve testability because your small methods will do exactly one thing.
def calc_first_nucleotide_position(po)
i = po.first
while nucleotide_at_position(i-1) == nucleotide_at_position(i)
raise "Assumption violated" if i == 1
i -= 1
end
i
end
# etc...
first_nucleotide_position = calc_first_nucleotide_position(positions)
last_nucleotide_position = calc_last_nucleotide_position(positions)
# etc...
Upvotes: 2
Reputation: 61081
What makes you think splitting the code up into multiple methods will hurt the readability? In my experience, splitting even small or medium sized pieces of code into multiple methods can greatly improve readability.
Upvotes: 4