Hacker News new | ask | show | jobs
by alanctgardner2 4930 days ago
To anyone who's wondering, it seems like 'and' and 'or' are the same as && and ||, but with lower precedence [0]. Does anyone have a good reason why they both exist? It's a pretty big gotcha.

[0] http://stackoverflow.com/questions/1426826/difference-betwee...

2 comments

It's an imported Perlism, back from the days of the old assert idiom `foo == bar or die`.

If `foo == bar` evaluates to true, the `or` is short-circuited, else it calls the built-in `die` function which kills the process.

More precisely && and || are meant to stand in boolean tests, whereas and and or are meant to tie expressions together DSL style, as an alternative to if/then, like so:

   @current_user.logged_in? or redirect_to login_path
   @current_user.can? :do_this or render :status => 403
   shirt.blue? and return bar
   put_suit_on or put_pants_on
That's a good example

  shirt.blue? and return bar
would be equivalent to

  return bar if shirt.blue?
You can do the same with or and unless.
I find the postfix if and unless far more readable than the Perlish and and or operators. The "or die" construction for asserts is really amusing though.
&&/|| can bite you just as well:

if first_user = User.find(4) && second_user = User.find(6) ... end

I may be missing something obvious here. How would this code bite you?
> first_user = User.find(4) && second_user = User.find(6)

It looks like it would evaluate as: first_user = (User.find(4) and second_user = User.find(6))

That is to say, the assignment comes after the boolean operation, which is unexpected.

Well, I expect

    first_user = User.find(4) && second_user = User.find(6)
to be literally equivalent to

    second_user = User.find(6)
    first_user = User.find(4) && second_user
I honestly can't see why you might want it to mean something else...

Edit: I see. if you do something like

    if (first_user = User.find(4) && second_user = User.find(6)) {
      ..
    }
it might bite you. You might expect it to be equivalent to

    first_user = User.find(4)
    second_user = User.find(6)
    if (first_user && second_user) {
      ..
    }
which I personally think is a very, very bad practice. Parenthesis should always be used when there's even the slightest possibility that you or another maintainer/contributor might be confused about.
Personally, I'm almost painfully verbose with my parens to avoid exactly this scenario. Better to be explicit about my intent to the interpreter and other coders.

Having an assignment that could be skipped by short-circuiting also seems like bad practice, but I realize it was designed to be a toy example

Skipping the second assignment if I don't need it is more of an optimisation. The "long form" would be,

first_user = User.find(4) if first_user second_user = User.find(6) if second_user ... end end

> Parenthesis should always be used when there's even the slightest possibility that you or another maintainer/contributor might be confused about.

Yes, but you can make the same point in favor of using "and" and "or" (and deprecating &&/||).