Hacker News new | ask | show | jobs
by aston 4852 days ago
Not to start a language war, but this blog post demonstrates two things Python got right that Ruby got wrong.

First, in Python, there's only one way to express a boolean "and". The && operator is left out.

Second, this post demonstrates a danger of allowing assignment via '=' evaluate to an expression (granted with less weird precedence rules it wouldn't turn out as bad in this case).

4 comments

Not to acknowledge we are at war, but allow me to react to your act of war.

This article demonstrates one thing that Ruby does awesomely, and python does not at all. Wether that makes Ruby better than Python.. well yes it does, no point in being diplomatic now, we're at war!

In Ruby there is only one way to express a boolean and, it goes: &&. Besides the boolean and there is also a binary operator with the name `and` which evaluates its left child, _and_ when it is true returns the value of its right child.

In this way it mimics the way we build sentences, that's smart. That's intuitive. That's Ruby.

"which evaluates its left child, _and_ when it is true returns the value of its right child"

I like the way you put that. I always stumble for a moment when asked to explain why using "and" and "&&" interchangeably is not a good idea because it can lead to subtle bugs in your program. Maybe a mnemonic would help to remember this more easily.

    left && right is true or false, but
    left and right is right when true
or something along those lines.
That seems more confusing, since they evaluate to the same thing.

    1.9.3p392 :001 > true && 1
     => 1 
    1.9.3p392 :002 > true and 1
     => 1 
    1.9.3p392 :003 > false && 1
     => false 
    1.9.3p392 :004 > false and 1
     => false 
    1.9.3p392 :005 > nil && 1
     => nil 
    1.9.3p392 :006 > nil and 1
     => nil 
Which is why explicitly checking for "true" or "false" in a conditional is unusual.
>In this way it mimics the way we build sentences, that's smart. That's intuitive. That's Ruby.

The problem is that "just like English" does not always translate to "intuitive for a programming language". Programmers don't have a problem with learning a new set of rules that don't work the same as their native language, because programming isn't (and shouldn't be) like writing a letter to your computer.

The simple rule is "if it's a binary operator, it has higher precedence than assignment". That rule works for almost every binary operator in almost every language. Show me an exception (like the comma operator in C), and I'll show you an operator that confuses the hell out of most programmers.

My biggest complaint is that you called Ruby's way "intuitive."

  | In this way it mimics the way we build sentences,
  | that's smart. That's intuitive. That's Ruby.
That's also a nod to Perl. :P
Both && and and are short-circuiting operators in Ruby. To eagerly evaluate both operator arguments you would need to use &.
"&" isn't even the same category, since it is a definable method and its meaning varies with the value on the left hand side.
I think Haskell wins out here since it has neither in the core language. Much easier to reason about. ;)
This explanation is an excellent way to teach and vs &&.
I don't think it actually works as a good explanation of the differences, the article it self does a good job by explaining the precedence rules which is the actual technical difference between the two. My explanation just shows the intuitive difference.
Python's "and" is equivalent to Ruby's "&&". Python has no equivalent to Ruby's "and" which is copied from Perl. In other words, Ruby has only one way to express a boolean "and", "&&", but the existence of the flow-control modifier "and" trips up new users constantly. Which is why this topic lands on HN regularly.
Which is, from the Python mindset, a flaw in Ruby the language.
And from a Ruby mindset, is a limitation in the Python language. :)
Yep. There's no right answer. I say, a pox on both their houses.

  (and predicate-1? predicate-2?)
As someone currently dealing with a lot of Java code, I love that Java only has && and not "and", it allows Java programmers to construct simple, easy-to-understand constructs like this:

  if (true && false == true) {
     return new BooleanFactory(true);
  } else {
     return new BooleanFactory(false);
  }
> Second, this post demonstrates a danger of allowing assignment via '=' evaluate to an expression (granted with less weird precedence rules it wouldn't turn out as bad in this case).

I think it's just an issue of precedence. Assignment evaluates to an expression in all Lisps, ML, Haskell, Scala, and Rust, without this issue.

Stricter typing can also solve the problem. If assignment evaluates to unit, as it does in ML/Haskell/Scala/Rust to name a few, then the attempt to perform the logical-and operation with unit and bool would throw (in a dynamically typed language) or won't compile (in a statically typed language).

Whether right or wrong, I personally prefer the Python way and I'm not a particular fan of Tim Toady. Especially when working in teams, it's simply easier if you don't have to make up rules, but it's clear upfront what to use, because there is no need for discussion.
This is not really a Tim Toady. && and and has different use cases.

One (ruby/perl: &&, python: and) is used to evaluate truthness of two expressions.

The other (ruby/perl: and, python: N/A) is more of a program flow operator. Now that I think about it.. If it is a Tim Toady, it is more of _if_ vs _and_ rather than _&&_ vs _and_.

Good point, I haven't thought about it that way.