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