Puts and return

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

On Tue, Sep 28, 2010 at 2:03 PM, Jim H. [email protected] wrote:

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?

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

Kirk H.

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.

On Tue, Sep 28, 2010 at 4:03 PM, Jim H. [email protected] wrote:

Expected output:
1 ok
too big
9 ok

Posted via http://www.ruby-forum.com/.


Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Github: rubyredrick (Rick DeNatale) · GitHub
Twitter: @RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale

Interesting. Thanks.

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

redirect_to and return if

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?

Rick Denatale wrote:

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.

On Tue, Sep 28, 2010 at 4:03 PM, Jim H. [email protected] wrote:

Expected output:
1 ok
too big
9 ok

Posted via http://www.ruby-forum.com/.


Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Github: rubyredrick (Rick DeNatale) · GitHub
Twitter: @RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale

On Tue, Sep 28, 2010 at 4:14 PM, Kirk H. [email protected] wrote:

&& 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.


Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Github: rubyredrick (Rick DeNatale) · GitHub
Twitter: @RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale

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. :slight_smile:

Rick Denatale wrote:

On Tue, Sep 28, 2010 at 4:14 PM, Kirk H. [email protected] wrote:

&& 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.


Rick DeNatale

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.

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

(puts “Too big”; break) if i > 5

Rick Denatale wrote:

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

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

Kirk H.

On Tue, Sep 28, 2010 at 4:03 PM, Jim H. [email protected] wrote:

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?

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

Jim H. wrote:

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

redirect_to and return if

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() if

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.

On Tue, Sep 28, 2010 at 4:29 PM, Jim H. [email protected] wrote:

Otherwise, why this is idiom so prevalent? Because 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 = 1
b = 2
x = 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.


Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Github: rubyredrick (Rick DeNatale) · GitHub
Twitter: @RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale

Rick DeNatale wrote:

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

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