puts and return

J

Jim Haungs

10.times do |i|
puts 'too big' and break if i > 5
puts "#{i} ok"
end

I would expect this loop to quit after printing 0 to 5, but it executes
all 10 times. I know "puts" return nil, but isn't "and" (as opposed to
&&) supposed to execute both sides of the expression even if one side
evaluates to false?

Expected output:
0 ok
1 ok
2 ok
3 ok
4 ok
5 ok
too big

Actual output:
0 ok
1 ok
2 ok
3 ok
4 ok
5 ok
too big
6 ok
too big
7 ok
too big
8 ok
too big
9 ok
 
K

Kirk Haines

10.times do |i|
=A0puts 'too big' and break if i > 5
=A0puts "#{i} ok"
end

I would expect this loop to quit after printing 0 to 5, but it executes
all 10 times. I know "puts" return nil, but isn't "and" (as opposed to
&&) supposed to execute both sides of the expression even if one side
evaluates to false?

&& is what you want, to get that effect.


Kirk Haines
 
R

Rick DeNatale

No, the only difference between && and 'and' is their parsing precedence.

And nearly every time I've seen and used instead of && I've found a bug.

10.times do |i|
=A0puts 'too big' and break if i > 5
=A0puts "#{i} ok"
end

I would expect this loop to quit after printing 0 to 5, but it executes
all 10 times. I know "puts" return nil, but isn't "and" (as opposed to
&&) supposed to execute both sides of the expression even if one side
evaluates to false?

Expected output:
0 ok
1 ok
2 ok
3 ok
4 ok
5 ok
too big

Actual output:
0 ok
1 ok
2 ok
3 ok
4 ok
5 ok
too big
6 ok
too big
7 ok
too big
8 ok
too big
9 ok



--=20
Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Github: http://github.com/rubyredrick
Twitter: @RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale
 
R

Rick DeNatale

&& is what you want, to get that effect.

No that doesn't work, since puts returns nil and nil || whatever
doesn't evaluate whatever.

And

puts "Too big" || break if i > 5

Doesn't cause the break.

I think this is because break really isn't an expression.

The best solution seems to be

if i > 5
puts "Too big"
break
end

Both because it works, and I don't put too much weight on marginally
shorter code.


--=20
Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Github: http://github.com/rubyredrick
Twitter: @RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale
 
J

Jim Haungs

Interesting. Thanks.

One sees control code like this in rails all the time:

redirect_to <somewhere> and return if <condition>

Never having looked at the return value from redirect_to (but guessing
it's always non-nil), I guess I assumed 'and' was the non-short-circuit
operator.

Otherwise, why this is idiom so prevalent? Because it looks more
English-like?
 
J

Jim Haungs

Yep. This is pretty much where I went with it, too. Pragmatic trumps
terse.

Now I'm going to go look for 'and's in my code. :)
 
B

Brian Candler

Rick said:
puts "Too big" || break if i > 5

Doesn't cause the break.

I think this is because break really isn't an expression.

I think that's parsed as:

puts("Too big" || break) if i > 5

and since "Too big" is always true, the RHS of || is never evaluated.
The best solution seems to be

if i > 5
puts "Too big"
break
end

I agree that's the clearest. For a one-liner I'd do:

(puts "Too big"; break) if i > 5
 
K

Kirk Haines

Ah, yeah. && results in the break, but not the puts. You are right.
Just use an if statement and call it good.


Kirk Haines
 
J

Jim Haungs

Digging deeper into the ruby syntax, it does not appear that there are
any boolean operators that are not short-circuited. There are the
logical operators & and |, but those appear to work only with integers,
a la bit-masks.

Amazing how much you can still learn about the corners of this language
even after years of use.
 
B

Brian Candler

Jim said:
One sees control code like this in rails all the time:

redirect_to <somewhere> and return if <condition>

Presumably that's in someone else's Rails application, not in Rails
itself.

That line is horrible. Firstly it's too clever, relying on relative
operator precedence between 'and' and 'if' which nobody remembers. And
secondly, it would break if there were ever a condition where
redirect_to did return false or nil(*).

But I understand the need for this pattern. I use this instead:

return redirect_to(<somewhere>) if <condition>

Regards,

Brian.

(*) IMO this is very dangerous, given that redirect_to doesn't even have
a documented return value:

http://api.rubyonrails.org/classes/ActionController/Redirecting.html#method-i-redirect_to

Looking at the source, the return value happens to be the body HTML
string. Today.
 
B

brabuhr

10.times do |i|
=A0puts 'too big' and break if i > 5
=A0puts "#{i} ok"
end

I would expect this loop to quit after printing 0 to 5, but it executes
all 10 times. I know "puts" return nil, but isn't "and" (as opposed to
&&) supposed to execute both sides of the expression even if one side
evaluates to false?

One option appears to be:

10.times do |i|
puts 'too big' and break if i > 5
puts "#{i} ok"
end

10.times do |i|
(puts 'too big'; break) if i > 5
puts "#{i} ok"
end

puts "done"

0 ok
1 ok
2 ok
3 ok
4 ok
5 ok
too big
6 ok
too big
7 ok
too big
8 ok
too big
9 ok
0 ok
1 ok
2 ok
3 ok
4 ok
5 ok
too big
done
 
R

Rick DeNatale

Interesting. Thanks.

One sees control code like this in rails all the time:

redirect_to <somewhere> and return if <condition>

Never having looked at the return value from redirect_to (but guessing
it's always non-nil), I guess I assumed 'and' was the non-short-circuit
operator.

Otherwise, why this is idiom so prevalent? =A0Because it looks more
English-like?

Because it was the recommended way to get around 'double render'
errors in the early days of Rails, and yes and is more English-like.

The problem is that the and and or operators have a surprisingly low
precedence, so for example
a =3D 1
b =3D 2
x =3D a >0 and b < 1

sets x to true, then evaluates b < 1 returning false and throws the result =
away.

I've seen too many problems caused by this that I eschew and in favor
of && almost? everywhere in my ruby code.


--=20
Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Github: http://github.com/rubyredrick
Twitter: @RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale
 
J

Jörg W Mittag

Rick said:
No, the only difference between && and 'and' is their parsing precedence.

And nearly every time I've seen and used instead of && I've found a bug.

I use it sometimes for control flow in DSL-ish situations. Here's a
line from a toy recursive descent parser:

@sign *= -1 if lookahead == '-' and consume

Here, I use `and` specifically as a way to denote control flow. I
agree that encountering a line like this somewhere in the middle of a
generic codebase is very surprising and often puzzling, but in this
case it is a highly stylized codebase with its own idioms.

For example, that same parser also contains the line

while parse_digit; end

or this one

parse_string or parse_array

Again, I would *never* write something like this in generic code, but
in this particular case it is my specific idiom to encode the EBNF
rules

string | digit

and

digit*

This allows me to distinguish between infrastructure code that is
there to support the parser, and the actual parsing rules themselves,
since the former *always* uses parentheses, `&&`, `||` and `!` and the
latter always uses `and`, `or` and `not` and doesn't use parentheses.

jwm
 
K

Kredaxx P.

The reason it doesn't work as you expect is because 'and' and puts.

puts' return value is nil. nil is falsy in conditions

nil and true #=> nil

and you are getting there:

(nil and break) if i > 5
which means break will never happen.

use ( puts(""); break ) if condition # if you want to achieve that, or
better yet

if condition
puts("")
break
end

if thats more clear
 

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,777
Messages
2,569,604
Members
45,218
Latest member
JolieDenha

Latest Threads

Top