Reputation:
I have this code in Ruby:
if @pass.nil?
badpass(@nick)
elsif not clt.correctpassword?(@nick, @pass)
badpass(@nick)
I wanted to condense it to a single line so I tried writing it as:
if not clt.correctpassword?(@nick, @pass) or @pass.nil?
badpass(@nick)
But then badpass(@nick)
doesn't get triggered for either cases, whereas it works in both cases in the top example.
Why does this happen?
Upvotes: 0
Views: 130
Reputation: 28870
In your revised code the tests are in the opposite order from the original. It's as if you had written:
if not clt.correctpassword?( @nick, @pass )
badpass( @nick )
elsif @pass.nil?
badpass( @nick )
end
Put the tests in the same order as the original and it will work like the original:
if @pass.nil? or not clt.correctpassword?( @nick, @pass )
badpass( @nick )
end
Remember that Ruby, like many other languages, uses short circuit evaluation for the logical operators and
, or
, &&
and ||
. This means that it evaluates the expression to the left of the operator first, and then only evaluates the expression to the right of the operator if it needs to.
BTW, many Rubyists would write it this way instead:
badpass( @nick ) if @pass.nil? or not clt.correctpassword?( @nick, @pass )
That does the same thing; it's just a matter of which style you prefer.
If the .correctpassword?
method is code that you can modify, then another nice option would be to add a nil test at the beginning of that method. In fact, you may as well test for nil on both nick
and pass
:
def correctpassword?( nick, pass )
return false if nick.nil? or pass.nil?
... the rest of your code here ...
end
Then when you call this method you can simply use:
if not clt.correctpassword?( @nick, @pass )
badpass( @nick )
end
or this simple code:
badpass( @nick ) unless clt.correctpassword?( @nick, @pass )
Upvotes: 4
Reputation: 106972
You should not use and
, or
or not
in conditions. They are for control flow and they offen lead to precedence problems in conditions.
Let's transform your code:
if @pass.nil?
badpass(@nick)
elsif not clt.correctpassword?(@nick, @pass)
badpass(@nick)
end
Make it more Ruby-like:
if !@pass
badpass(@nick)
elsif !clt.correctpassword?(@nick, @pass)
badpass(@nick)
end
Combine conditions:
if !@pass || !clt.correctpassword?(@nick, @pass)
badpass(@nick)
end
Simplefy condition (De Morgan's law)
if !(@pass && clt.correctpassword?(@nick, @pass))
badpass(@nick)
end
Or even more Ruby-like:
badpass(@nick) unless @pass && clt.correctpassword?(@nick, @pass)
And I agree with @MichaelGeary that you should move the check for the existence of @pass
into the correctpassword?
method...
Upvotes: 3