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

···

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

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

Kirk Haines

···

On Tue, Sep 28, 2010 at 2:03 PM, Jim Haungs <jhaungs@gmail.com> 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?

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 Haungs <jhaungs@gmail.com> 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?

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

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

···

On Tue, Sep 28, 2010 at 4:03 PM, Jim Haungs <jhaungs@gmail.com> 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?

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.

···

On Tue, Sep 28, 2010 at 4:14 PM, Kirk Haines <wyhaines@gmail.com> wrote:

On Tue, Sep 28, 2010 at 2:03 PM, Jim Haungs <jhaungs@gmail.com> 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.

--
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 <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?

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 Haungs <jhaungs@gmail.com> 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

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

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

Kirk Haines

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

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 Haines <wyhaines@gmail.com> 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

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

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

···

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

Jim Haungs wrote:

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.

···

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

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.

···

On Tue, Sep 28, 2010 at 4:29 PM, Jim Haungs <jhaungs@gmail.com> wrote:

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?

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

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

···

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

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

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