Help with while condition OR condition

B

Bill W.

Hi everyone,

This is my first post, so I hope I don't sound too inexperienced..

I'm trying to teach myself Ruby, and have run into an issue with a while
statement that will break if an input is "exit" or "quit".
As of right now, it works if exit is input, but not quit

I know I am completely misusing the entire thing, but here is what I
came up with:

EXIT = "exit" #need constants since Ruby gets pissed at string literals
QUIT = "quit" #in a comparison

print "Input: "
input = gets
while input.chomp.downcase != (EXIT || QUIT) #only works for exit

#Do something

print "Input: " #pick up the next input and check it
input = gets
end

I know that Ruby has a lot of shortcuts, but if you post any please
explain how they work (or provide a link to a good explanation.

Thanks!
 
S

Steve Klabnik

[Note: parts of this message were removed to make it a legal post.]

Don't do that, just use eql?

begin
print "input: "
input = gets.chomp.downcase
end while not (input.eql? "exit" or input.eql? "quit")
 
C

Christopher Dicely

Hi everyone,

This is my first post, so I hope I don't sound too inexperienced..

I'm trying to teach myself Ruby, and have run into an issue with a while
statement that will break if an input is "exit" or "quit".
As of right now, it works if exit is input, but not quit

I know I am completely misusing the entire thing, but here is what I
came up with:

EXIT =3D "exit" =C2=A0#need constants since Ruby gets pissed at string li= terals
QUIT =3D "quit" =C2=A0#in a comparison

print "Input: "
input =3D gets
while input.chomp.downcase !=3D (EXIT || QUIT) #only works for exit

The || operator returns the operand on the left if it is "true-ish"
(anything other than nil or false), otherwise it evaluates and returns
the operand on the right. So (EXIT || QUIT) where EXIT=3D"exit" just
evaluates to "exit".

You could do this with the || between two comparisons (rather than two
options in one comparison).

Also, Ruby has no problem with comparisons against string literals;
what made you think it did?
 
J

John Feminella

This line doesn't behave in the way I think you expect:
while input.chomp.downcase !=3D (EXIT || QUIT) #only works for exit

This says, "check if the downcased input is not equal to the value of
the expression `EXIT || QUIT`". What is the value of that expression?
In this case, it will resolve to EXIT, since the string "exit" is not
false or nil and is thus true. The value of QUIT is never evaluated.
So, if the input is not equal to exit, the while loop continues.

Why is that? In Ruby, all expressions have both a "value" and a
"truthiness". An expression is "falsy" if it evaluates to either
`false` or `nil`; otherwise it is `truthy`. In the case of an
expression like `foo || bar`, the truth table would look like this:

* foo is truthy, bar is truthy: result is `foo` and truthy
* foo is truthy, bar is falsy: result is `foo` and truthy
* foo is falsy, bar is truthy: result is `bar` and truthy
* foo is falsy, bar is falsy: result is `bar` and falsy

So you can see that in your case, foo is EXIT and bar is QUIT, both of
which are truthy values; thus the expression is "exit". To get what
you what want, try something like this:

command =3D input.chomp.downcase
while command !=3D "exit" || command !=3D "quit" ...

Or, more succinctly:

case command
when "exit", "quit"
puts "exiting!"; ...
else
# do stuff
end

~ jf
--
John Feminella
Principal Consultant, BitsBuilder
LI: http://www.linkedin.com/in/johnxf
SO: http://stackoverflow.com/users/75170/
 
J

John Feminella

Oops, small typo:

while command !=3D "exit" || command !=3D "quit" ...

should be:

while command !=3D "exit" && command !=3D "quit" ...
--
John Feminella
Principal Consultant, BitsBuilder
LI: http://www.linkedin.com/in/johnxf
SO: http://stackoverflow.com/users/75170/



This line doesn't behave in the way I think you expect:
while input.chomp.downcase !=3D (EXIT || QUIT) #only works for exit

This says, "check if the downcased input is not equal to the value of
the expression `EXIT || QUIT`". What is the value of that expression?
In this case, it will resolve to EXIT, since the string "exit" is not
false or nil and is thus true. The value of QUIT is never evaluated.
So, if the input is not equal to exit, the while loop continues.

Why is that? In Ruby, all expressions have both a "value" and a
"truthiness". An expression is "falsy" if it evaluates to either
`false` or `nil`; otherwise it is `truthy`. In the case of an
expression like `foo || bar`, the truth table would look like this:

* foo is truthy, bar is truthy: result is `foo` and truthy
* foo is truthy, bar is falsy: result is `foo` and truthy
* foo is falsy, bar is truthy: result is `bar` and truthy
* foo is falsy, bar is falsy: result is `bar` and falsy

So you can see that in your case, foo is EXIT and bar is QUIT, both of
which are truthy values; thus the expression is "exit". To get what
you what want, try something like this:

=C2=A0 =C2=A0command =3D input.chomp.downcase
=C2=A0 =C2=A0while command !=3D "exit" || command !=3D "quit" ...

Or, more succinctly:

=C2=A0 =C2=A0case command
=C2=A0 =C2=A0when "exit", "quit"
=C2=A0 =C2=A0 =C2=A0puts "exiting!"; ...
=C2=A0 =C2=A0else
=C2=A0 =C2=A0 =C2=A0# do stuff
=C2=A0 =C2=A0end

~ jf
--
John Feminella
Principal Consultant, BitsBuilder
LI: http://www.linkedin.com/in/johnxf
SO: http://stackoverflow.com/users/75170/
 
J

Joel VanderWerf

Hi everyone,

This is my first post, so I hope I don't sound too inexperienced..

I'm trying to teach myself Ruby, and have run into an issue with a while
statement that will break if an input is "exit" or "quit".
As of right now, it works if exit is input, but not quit

I know I am completely misusing the entire thing, but here is what I
came up with:

EXIT = "exit" #need constants since Ruby gets pissed at string literals
QUIT = "quit" #in a comparison

print "Input: "
input = gets
while input.chomp.downcase != (EXIT || QUIT) #only works for exit

It can help to take apart expressions in irb (interactive ruby):

$ irb=> false
#Do something

print "Input: " #pick up the next input and check it
input = gets
end

I know that Ruby has a lot of shortcuts, but if you post any please
explain how they work (or provide a link to a good explanation.

Something to tinker with:

print "Input: "
while input = gets
case s = input.chomp.downcase
when "exit", "quit"
puts "You wanted to #{s} this mighty fine program?"
break
else
puts "Why do you say '#{s}'?"
print "Input: "
end
end
puts "Done."
 
H

Hashmal

`(EXIT || QUIT)` will always return "exit" as EXIT is never `nil` or
`false`, so in your case, the input string is never checked against `QUIT`.

Try this:

print "Input: "
input = gets

until ["exit", "quit"].include? input.chomp.downcase
# Do something
print "Input: "
input = gets
end

As you can see you can do it without constants. the method `include?`
checks if an element exists in the array. `until` is basically an
inverted `while`.
 
B

Bill W.

Wow! I would say this is the most replies I have ever had on a
programming topic!

Thanks for the in-depth description of how || works, I was WAY off.

I tried this with until already once, but I had the rest of it wrong and
it failed.

command = input.chomp.downcase
until ["exit", "quit"].include? input.chomp.downcase
are both exactly the type of shortcuts i would have never though of!

Thanks again!
 
J

Josh Cheek

[Note: parts of this message were removed to make it a legal post.]

EXIT = "exit" #need constants since Ruby gets pissed at string literals
QUIT = "quit" #in a comparison
It doesn't get pissed at string literals in comparison, its just that it was
able to tell that the way you were comparing didn't make sense (because
string literal is known at time you wrote it, not dynamically looked up, so
the comparison is also known, and doesn't make sens). So it was warning you
of the issue. It didn't complain when you stored then in vars/constants,
because it doesn't know their value until runtime. They could hypothetically
be false or nil, so it isn't conspicuously an error.

e.g.

if "some literal"
# do something
end # !> string literal in condition

if "some literal" || "other"
# do something
end # !> string literal in condition
 
7

7stud --

Hi,

A lot of beginners make the same mistake you did. 'Compound
conditionals' have to be written like separate conditionals and then
hooked together with an 'or' or 'and'. For instance if you wanted to do
something only if a number were greater than 5 and less then 10, you
would do this:

x > 5
x < 10
and

if x > 5 and x < 10
#do something
end

Everyone should use 'and' and 'or' by default instead of && and ||.
Code reads better that way. Only if you have a specific reason to,
should you use && or ||.

Good luck.
 
J

John Feminella

Everyone should use 'and' and 'or' by default instead of && and ||.
Code reads better that way. =C2=A0Only if you have a specific reason to,
should you use && or ||.

It's not a good idea to make a blanket rule like that, imo. The "and"
keyword is not really a substitute for "&&", since it has different
precedence. It's best viewed as a control flow modifier (like "if" or
"unless" when at the end of an expression), rather than a true logical
operator.

If you don't know that it's not quite the same, this can get you into
big trouble by leading to subtle bugs. Consider this code, for
instance:
=3D> false

# Using &&=3D> :abort_launch # Looks good here.

# Using "and"=3D> false # Uh-oh! We didn't get the `:abort_launch` we were expecting...

~ jf
--
John Feminella
Principal Consultant, BitsBuilder
LI: http://www.linkedin.com/in/johnxf
SO: http://stackoverflow.com/users/75170/
 
B

Brian Candler

7stud -- wrote in post #997311:
In ruby, everyone should use 'and' and 'or' by default instead of && and
||.

I would advise exactly the opposite: there are many traps for the unwary
if you use 'and' and 'or'. Two prime examples:
=> false
SyntaxError: compile error
(irb):7: syntax error, unexpected kNOT

Use '||' and '!' respectively and you won't have a problem.
 
P

Phillip Gawlowski

Brian Candler wrote in post #997379:

lol.

Should've tried the code first:

irb(main):001:0> val = 10
=> 10
irb(main):002:0> ok = val < 3 || val > 5
=> true
irb(main):003:0> ok
=> true
irb(main):004:0> a = true
=> true
irb(main):005:0> b = !a
=> false

Using *only* "or" or "not" obviously doesn't lead to the expected
results, while using || and ! do.

--
Phillip Gawlowski

Though the folk I have met,
(Ah, how soon!) they forget
When I've moved on to some other place,
There may be one or two,
When I've played and passed through,
Who'll remember my song or my face.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top