Operator prescedence weirdness

All,

Can anyone point me in the direction of what I'm missing here? I'd expect
the 5th, 6th and 7th commands to all return 'true':

2.2.1 :001 > a = {}
=> {}
2.2.1 :002 > a[:foo] = :bar
=> :bar
2.2.1 :003 > a.has_key? :foo
=> true
2.2.1 :004 > a[:foo]
=> :bar
2.2.1 :005 > a.has_key? :foo && a[:foo] == :bar
=> false
2.2.1 :006 > a.has_key? :foo && (a[:foo] == :bar)
=> false
2.2.1 :007 > (a.has_key? :foo) && a[:foo] == :bar
=> true

I realise I can just do a[:foo] == bar, as a[:foo] will return nil if
there's no :foo member.

Peter

Can anyone point me in the direction of what I'm missing here? I'd expect
the 5th, 6th and 7th commands to all return 'true':

...

2.2.1 :005 > a.has_key? :foo && a[:foo] == :bar
=> false
2.2.1 :006 > a.has_key? :foo && (a[:foo] == :bar)
=> false
2.2.1 :007 > (a.has_key? :foo) && a[:foo] == :bar
=> true

This is one of those cases where not using the optional parentheses on
a method call will bite you. Without even looking up the order of
precedence, I can tell you that using parens will fix it. Try:

  a.has_key?(:foo) && a[:foo] == :bar

This returns true.

-Dave

···

On Fri, Oct 9, 2015 at 2:27 PM, Peter Hicks <peter.hicks@poggs.co.uk> wrote:

--
Dave Aronson, consulting software developer of Codosaur.us,
PullRequestRoulette.com, Blog.Codosaur.us, and Dare2XL.com.

The issue is that the right side expression is evaluated first. Ruby parses this and sees has_key? and some expression. Since there are no parent then it assumes you want to pass the entire expression to has_key?, so it reduces that expression first before passing it to has_key?. When you add parents you are being explicit about how expressions should be reduced

Josh

···

Sent from my iPhone

On Oct 9, 2015, at 2:27 PM, Peter Hicks <peter.hicks@poggs.co.uk> wrote:

All,

Can anyone point me in the direction of what I'm missing here? I'd expect the 5th, 6th and 7th commands to all return 'true':

2.2.1 :001 > a = {}
=> {}
2.2.1 :002 > a[:foo] = :bar
=> :bar
2.2.1 :003 > a.has_key? :foo
=> true
2.2.1 :004 > a[:foo]
=> :bar
2.2.1 :005 > a.has_key? :foo && a[:foo] == :bar
=> false
2.2.1 :006 > a.has_key? :foo && (a[:foo] == :bar)
=> false
2.2.1 :007 > (a.has_key? :foo) && a[:foo] == :bar
=> true

I realise I can just do a[:foo] == bar, as a[:foo] will return nil if there's no :foo member.

Peter

Hi Dave

···

On Fri, 9 Oct 2015 at 19:40 Dave Aronson <ruby-talk.list.2.TRex@codosaur.us> wrote:

This is one of those cases where not using the optional parentheses on
a method call will bite you. Without even looking up the order of
precedence, I can tell you that using parens will fix it. Try:

  a.has_key?(:foo) && a[:foo] == :bar

This returns true.

"Optional parentheses" are the two key words here - thanks, I didn't
realise they were the problem.

Peter

Or use 'and' instead of '&&'. (I think, I don't have ruby on my phone to
verify)

···

On 10/10/2015 6:14 AM, <jb3689@yahoo.com> wrote:

The issue is that the right side expression is evaluated first. Ruby
parses this and sees has_key? and some expression. Since there are no
parent then it assumes you want to pass the entire expression to has_key?,
so it reduces that expression first before passing it to has_key?. When you
add parents you are being explicit about how expressions should be reduced

Josh

Sent from my iPhone

> On Oct 9, 2015, at 2:27 PM, Peter Hicks <peter.hicks@poggs.co.uk> wrote:
>
> All,
>
> Can anyone point me in the direction of what I'm missing here? I'd
expect the 5th, 6th and 7th commands to all return 'true':
>
> 2.2.1 :001 > a = {}
> => {}
> 2.2.1 :002 > a[:foo] = :bar
> => :bar
> 2.2.1 :003 > a.has_key? :foo
> => true
> 2.2.1 :004 > a[:foo]
> => :bar
> 2.2.1 :005 > a.has_key? :foo && a[:foo] == :bar
> => false
> 2.2.1 :006 > a.has_key? :foo && (a[:foo] == :bar)
> => false
> 2.2.1 :007 > (a.has_key? :foo) && a[:foo] == :bar
> => true
>
> I realise I can just do a[:foo] == bar, as a[:foo] will return nil if
there's no :foo member.
>
>
> Peter

Or use 'and' instead of '&&'.

Aiieeee! No no, 1_000_000.times { no! } Please do not resort to such
horrid kluges as using those *flow control operators* when you should
be using a *boolean operator*!

Better yet, just forget the verbal versions even exist. Unless you're
coming from Perl, they are unnatural and misleading. See
Ruby Gotchas - Google Slides (the slides from my Ruby Gotchas
presentation) for details, the slides titled "and != &&" and "or !=

".

-Dave

···

On Fri, Oct 9, 2015 at 5:21 PM, Matthew Kerwin <matthew@kerwin.net.au> wrote:

--
Dave Aronson, consulting software developer of Codosaur.us,
PullRequestRoulette.com, Blog.Codosaur.us, and Dare2XL.com.

> Or use 'and' instead of '&&'.

Aiieeee! No no, 1_000_000.times { no! } Please do not resort to such
horrid kluges as using those *flow control operators* when you should
be using a *boolean operator*!

"and" is the same boolean operator as "&&" with the same semantics with
regard to short circuiting (which makes both useful for flow control). The
only difference is precedence which is much lower in case of "and". Why are
you making this distinction between "boolean operators" and "flow control
operators"?

Better yet, just forget the verbal versions even exist. Unless you're
coming from Perl, they are unnatural and misleading.

Every language has its idioms. That "and" and "or" are "banned" (see [1])
is completely new to me. And I don't see an issue with using them. They are
handy for exactly these kinds of situations and where you want to make code
human readable. Of course you need to be aware of their properties - but
that is true for all the other language constructs as well.

See
Ruby Gotchas - Google Slides (the slides from my Ruby Gotchas
presentation) for details, the slides titled "and != &&" and "or !=
>>".

What style guide are you referring to? I would like to hear some more
reasoning. The style guide I found [1] just states not to do it but does
not give a reason as far as I can see.

Kind regards

robert

[1] GitHub - rubocop/ruby-style-guide: A community-driven Ruby coding style guide

···

On Sat, Oct 10, 2015 at 1:48 AM, Dave Aronson < ruby-talk.list.2.TRex@codosaur.us> wrote:

On Fri, Oct 9, 2015 at 5:21 PM, Matthew Kerwin <matthew@kerwin.net.au> > wrote:

--
[guy, jim, charlie].each {|him| remember.him do |as, often| as.you_can -
without end}
http://blog.rubybestpractices.com/

...

Please do not resort to such
horrid kluges as using those *flow control operators* when you should
be using a *boolean operator*!

"and" is the same boolean operator as "&&" with the same semantics with
regard to short circuiting (which makes both useful for flow control). The
only difference is precedence which is much lower in case of "and". Why are
you making this distinction between "boolean operators" and "flow control
operators"?

Precedence makes a huge difference. The lower precedence of "and" and
"or" makes them horribly misleading in a normal boolean expression
where you're trying to calculate the resulting truth value. This is a
violation of one of Ruby's core principles, that of Least
Astonishment. They are much more commonly used (at least in correct
code) for flow control, in Perlish idioms such as "do_this and
do_that" (do this, and only if that succeeded, assuming that it
returns a boolean value to indicate success or failure, proceed to do
that) and "do_something or give_error_message" (do something, and if
that fails, making the same assumption, then give an error message).
Ruby has perfectly good idioms for these situations, that is even
clearer (no surprise when comparing against Perl): "do_that if
do_this" and "give_error_message unless do_something".

Better yet, just forget the verbal versions even exist. Unless you're
coming from Perl, they are unnatural and misleading.

Every language has its idioms. That "and" and "or" are "banned" (see [1]) is
completely new to me. And I don't see an issue with using them. They are
handy for exactly these kinds of situations and where you want to make code
human readable. Of course you need to be aware of their properties - but
that is true for all the other language constructs as well.

But their properties are not at all obvious! They masquerade as the
normal boolean operators, simply more humanized versions of && and ||,
while they certainly are not at all equivalent, leading to astonishing
bugs. It's usually not until one has been sorely bitten by such a
bug, or see it discussed, that one finds out about this vital
difference.

See http://bit.ly/RubyGotchas (the slides from my
Ruby Gotchas presentation) for details, the slides
titled "and != &&" and "or != ||".

What style guide are you referring to? I would like to hear some more
reasoning. The style guide I found [1] just states not to do it but does not
give a reason as far as I can see.

...

[1] https://github.com/bbatsov/ruby-style-guide#no-and-or-or

Frankly I now forget which one I had in mind, but it was most likely
either that one or Github's, which borrows heavily from it. You're
right that it is light on the reasoning. I believe it's because the
use of "and" and "or" looks tempting to people (not necessarily even
just newbies!) trying to make the code more human-readable, but
introducing subtle bugs that arise from the difference in precedence.
Both guides say "It's just not worth it"; I believe that what they
mean is that the slight better readability is not worth the pain of
creating, encountering, and debugging such bugs... especially when
these operators just won't do what you probably want (if you're
looking for a calculation of a boolean value resulting from combining
several things).

I'll put in a pull request for BBatsov's, providing an example for
better clarity of the bug-potential, plus offering the above
Ruby-idiomatic snippets as alternatives.

-Dave

···

On Sun, Oct 11, 2015 at 2:07 PM, Robert Klemme <shortcutter@googlemail.com> wrote:

On Sat, Oct 10, 2015 at 1:48 AM, Dave Aronson > <ruby-talk.list.2.TRex@codosaur.us> wrote:

--
Dave Aronson, consulting software developer of Codosaur.us,
PullRequestRoulette.com, Blog.Codosaur.us, and Dare2XL.com.

From Avdi Grimm:
http://devblog.avdi.org/2014/08/26/how-to-use-rubys-english-andor-operators-without-going-nuts/

He basically says "they're flow control, not logic". The difference in
precedence can be confusing or surprising. If someone chooses 'and' because
it's more readable than '&&', but fails to take into consideration that
they've change their precedence, it becomes dangerous. In many ways, it's
easier to just "forget that they exist", since && and || will cover your
use cases 99% of the time.

-J

···

On Sun, Oct 11, 2015 at 11:08 AM Robert Klemme <shortcutter@googlemail.com> wrote:

On Sat, Oct 10, 2015 at 1:48 AM, Dave Aronson < > ruby-talk.list.2.TRex@codosaur.us> wrote:

On Fri, Oct 9, 2015 at 5:21 PM, Matthew Kerwin <matthew@kerwin.net.au> >> wrote:

> Or use 'and' instead of '&&'.

Aiieeee! No no, 1_000_000.times { no! } Please do not resort to such
horrid kluges as using those *flow control operators* when you should
be using a *boolean operator*!

"and" is the same boolean operator as "&&" with the same semantics with
regard to short circuiting (which makes both useful for flow control). The
only difference is precedence which is much lower in case of "and". Why are
you making this distinction between "boolean operators" and "flow control
operators"?

Better yet, just forget the verbal versions even exist. Unless you're
coming from Perl, they are unnatural and misleading.

Every language has its idioms. That "and" and "or" are "banned" (see [1])
is completely new to me. And I don't see an issue with using them. They are
handy for exactly these kinds of situations and where you want to make code
human readable. Of course you need to be aware of their properties - but
that is true for all the other language constructs as well.

See
http://bit.ly/RubyGotchas (the slides from my Ruby Gotchas
presentation) for details, the slides titled "and != &&" and "or !=
>>".

What style guide are you referring to? I would like to hear some more
reasoning. The style guide I found [1] just states not to do it but does
not give a reason as far as I can see.

Kind regards

robert

[1] https://github.com/bbatsov/ruby-style-guide#no-and-or-or

--
[guy, jim, charlie].each {|him| remember.him do |as, often| as.you_can -
without end}
http://blog.rubybestpractices.com/

Dave, thank you for going through the effort to share your reasoning!

>
...
>> Please do not resort to such
>> horrid kluges as using those *flow control operators* when you should
>> be using a *boolean operator*!
>
> "and" is the same boolean operator as "&&" with the same semantics with
> regard to short circuiting (which makes both useful for flow control).
The
> only difference is precedence which is much lower in case of "and". Why
are
> you making this distinction between "boolean operators" and "flow control
> operators"?

Precedence makes a huge difference. The lower precedence of "and" and
"or" makes them horribly misleading in a normal boolean expression
where you're trying to calculate the resulting truth value. This is a
violation of one of Ruby's core principles, that of Least
Astonishment.

People tend to forget that the principle of least surprise applies to Matz.
This is an important restriction that changes semantics quite a bit. See
http://www.artima.com/intv/ruby4.html

They are much more commonly used (at least in correct
code) for flow control, in Perlish idioms such as "do_this and
do_that" (do this, and only if that succeeded, assuming that it
returns a boolean value to indicate success or failure, proceed to do
that) and "do_something or give_error_message" (do something, and if
that fails, making the same assumption, then give an error message).
Ruby has perfectly good idioms for these situations, that is even
clearer (no surprise when comparing against Perl): "do_that if
do_this" and "give_error_message unless do_something".

Actually I use both idioms. I would use "if" only if "do_this" is a test of
some kind. I would use "and" if "do_this" was some kind of task that can
end successfully or not and I want to "do_that" only if "do_this" was
successful.

>> Better yet, just forget the verbal versions even exist. Unless you're
>> coming from Perl, they are unnatural and misleading.
>
> Every language has its idioms. That "and" and "or" are "banned" (see
[1]) is
> completely new to me. And I don't see an issue with using them. They are
> handy for exactly these kinds of situations and where you want to make
code
> human readable. Of course you need to be aware of their properties - but
> that is true for all the other language constructs as well.

But their properties are not at all obvious!

Define "obvious". :slight_smile: Seriously, all language constructs have properties
that cannot be seen immediately. We have to learn them. Maybe you mean with
"obvious" here something like "function the same was as in other languages
X, Y and Z". But these languages often do not have something like operator
"and" and people will have to learn this new thing anyway.

They masquerade as the
normal boolean operators, simply more humanized versions of && and ||,
while they certainly are not at all equivalent, leading to astonishing
bugs. It's usually not until one has been sorely bitten by such a
bug, or see it discussed, that one finds out about this vital
difference.

I can only speak for me: I learned about the different precedence right
from the start so to me they never "masqueraded" as anything else.

>> See http://bit.ly/RubyGotchas (the slides from my
>> Ruby Gotchas presentation) for details, the slides
>> titled "and != &&" and "or != ||".
>
> What style guide are you referring to? I would like to hear some more
> reasoning. The style guide I found [1] just states not to do it but does
not
> give a reason as far as I can see.
...
> [1] https://github.com/bbatsov/ruby-style-guide#no-and-or-or

Frankly I now forget which one I had in mind, but it was most likely
either that one or Github's, which borrows heavily from it. You're
right that it is light on the reasoning. I believe it's because the
use of "and" and "or" looks tempting to people (not necessarily even
just newbies!) trying to make the code more human-readable, but
introducing subtle bugs that arise from the difference in precedence.
Both guides say "It's just not worth it"; I believe that what they
mean is that the slight better readability is not worth the pain of
creating, encountering, and debugging such bugs... especially when
these operators just won't do what you probably want (if you're
looking for a calculation of a boolean value resulting from combining
several things).

I cannot really say how much confusion they create in the community, for me
that problem does not exist. From my memory (which is feeble) I have seen
far more threads here about the confusing properties of class variables
than of "and". :slight_smile:

I'll put in a pull request for BBatsov's, providing an example for
better clarity of the bug-potential, plus offering the above
Ruby-idiomatic snippets as alternatives.

It's always good to make reasoning of such rules transparent. You are doing
the community a good service! Thank you!

Kind regards

robert

···

On Sun, Oct 11, 2015 at 8:45 PM, Dave Aronson < ruby-talk.list.2.TRex@codosaur.us> wrote:

On Sun, Oct 11, 2015 at 2:07 PM, Robert Klemme > <shortcutter@googlemail.com> wrote:
> On Sat, Oct 10, 2015 at 1:48 AM, Dave Aronson > > <ruby-talk.list.2.TRex@codosaur.us> wrote:

--
[guy, jim, charlie].each {|him| remember.him do |as, often| as.you_can -
without end}
http://blog.rubybestpractices.com/