I am currently working on a project where I have code that looks like this:
# the first return is the one causing problems
def collect
return Hash["IdentANode", Array[@id, ",", @ident_a_node.collect]] unless @ident_a_node.nil? and @id.nil?
return Hash["IdentANode", @id] unless @id.nil?
end
Where I use the unless operator to conditionally execute the return statement. For some reason this code still executes even if @ident_a_node is nil. When executing I get this message:
IdentANode.rb:14:in
collect': undefined methodcollect’ for
nil:NilClass (NoMethodError)
Which confuses me because I had thought that the unless keyword would prevent this from happening. When I change the statement to this form:
if not @ident_a_node.nil? and not @id.nil?
return Hash["IdentANode", Array[@id, ",", @ident_a_node.collect]]
end
or this form:
return Hash["IdentANode", Array[@id, ",", @ident_a_node.collect]] if not @ident_a_node.nil? and not @id.nil?
The return statement is not executed, what gives? Why is there a difference between these two statements? Does having multiple conditions with the unless keyword cause problems?
Any ideas would be appreciated
You’ve got a logic failure in there. You’re testing that they’re both
nilto avoid running it when you should be testing if either isnil. You’ve probably gotten yourself into this situation by having too many layers of negation. Anything more than one is unacceptable.In other words, you can get away with “if it’s not raining out” but shouldn’t use things like “unless the
is_not_rainingflag is not set to the inverse of false”.My personal opinion is that trailing conditions should not be used unless it’s obvious that they’re present. As you can see in your example, you have to scroll horizontally to find the condition, hiding important information from the developer.
As a matter of style, do not use
notwhen!will do the same job. Secondly, you’re testing specifically againstnilwhen you probably just want a defined value of some kind.Other issues include using
Hash[]andArray[]which are surely artifacts of using a language which requires them. Ruby, like JavaScript, allows implicit declaration of these using{ }and[ ]respectively.A proper Ruby-styled version of your code is: