I am looking for a concise way to deal with the following situation: Given a variable (in practince, an instance variable in a class, though I don't think this matters here), which is known to be either nil or hold some Integer. If it is an Integer, the variable should be incremented. If it is nil, it should be initialized with 1.
These are obvious solutions to this, taking @counter as the variable to deal with:
# Separate the cases into two statements
@counter ||= 0
@counter += 1
or
# Separate the cases into one conditional
@counter = @counter ? (@counter + 1) : 1
I don't like these solutions because they require to repeat the name of the variable. The following attempt failed:
# Does not work
(@counter ||= 0) += 1
This can't be done, because the result of the assignment operators is not an lvalue, though the actual error message is a bit obscure. In this case, you get the error _unexpected tOP_ASGN, expecting end_.
Is there a good idiom to code my problem, or do I have to stick with one of my clumsy solutions?
The question is clear:
nil or an integer. If nil the variable is to be set equal to 1, else it is to be set equal to its value plus 1.First, two points.
1.". This contradicts the statement that the variable is known to be nil or an integer, meaning that it has already been initialized, or more accurately, defined. In the case of an instance variable, this distinction is irrelevant as Ruby initializes undefined instance variables to nil when they are referenced as rvalues. It's an important distinction for local variables, however, as an exception is raised when an undefined local variable is referenced as an rvalue.nil or an integer. They are therefore irrelevant. If the OP wishes to broaden the question to allow the variable to hold objects other than nil or an integer (an array or hash, for example), a separate question should be asked.What criteria should be used in deciding what code is best? Of the various possibilities that have been mentioned, I do not see important differences in efficiency. Assuming that to be the case, or that relative efficiency is not important in the application, we are left with readability (and by extension, maintainability) as the sole criterion. If x equals nil or an integer, or is an undefined instance variable, perhaps the clearest code is the following:
x = 0 if x.nil?
x += 1
or
x = x.nil? ? 1 : x+1
Ever-so-slightly less readable:
x = (x || 0) + 1
and one step behind that:
x = x.to_i + 1
which requires the reader to know that nil.to_i #=> 0.
The OP may regard these solutions as "clumsy", but I think they are all beautiful.
Can an expression be written that references x but once? I can't think of a way and one has not been suggested in the comments, so if there is a way (doubtful, I believe) it probably would not meet the test for readability.
Consider now the case where the local variable x may not have been defined. In that case we might write:
x = (defined?(x) ? (x || 0) : 0) + 1
defined? is a Ruby keyword.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With