Overview
Avdi Grimm has a recent post noting the use of “and” and “or” Ruby keywords as essentially control flow operators, and hinting on their Perl origins. This instantly recalled several mental notes of old Perl programs, so I though I’d put out a few quick notes on the Perl equivalents for Ruby programmers not versed in Perl 5.
Perl Semantics
Perl actually borrows the precedence rules of “&&” and “||” from C, though I’m not entirely convinced the Perl and Ruby semantics of “and” and “or” are identical. We have to remember that Larry Wall is a linguist, and that some of Perl’s idiosyncrasies are due more to human considerations than machine. Programming Perl has several pages of great content on “and” and “or”. For example, here’s an excerpt from the circa 2000 version of Programming Perl:
But you can’t just up and replace instances of || with or. Suppose you change this:
$xyz = $x || $y || $z;
to this:
$xyz = $x or $y or $z; # WRONG
That wouldn’t do the same thing at all! The precedence of the assignment is higher than “or” but lower than ||, so it would always assign $x to $xyz, and then do the ors. To get the same effect as ||, you’d have to write:
$xyz = ($x or $y or $z);
The moral of the story is that you must still learn precedence (or use parentheses) no matter which variety of logical operator you use.
What Avdi says about precedence and control flow seems correct, though the reasons for it–in Perl at least–is to differentiate between two subtly distinct human linguistic semantics. For example, consider the following two English statements.
- I’m either traveling by car or just staying home.
- I’m either traveling by car or by train.
At first glance the semantics seem identical, but on closer inspection they are completely different. Let’s look at each.
I’m either traveling by car or just staying home.
In Perl, this is the equivalent of:
$traveling_by_car = can_use_car($me) or stay_home($me);
The semantics of or is to describe consequence (aka control flow) in a specific order. Either I’m traveling_by_car(), or else screw the whole thing and I’ll just stay_home() instead, in which case it makes little difference what the value of $traveling_by_car is. In other words, the semantics of the assignment trump that of the consequence, and should the consequence occur (which in this case probably has side effects), the assignment probably doesn’t matter. This is why Perl users often use or in the following context instead of ||:
open FOO, $file or die “a horrible death: $!”;
@lines = <FOO> or die “$file is empty?”;
I’m either traveling by car or by train.
In English, this is a misleading statement of truth for several reasons.
- What we mean is that one of the two options is true, but one and only one. As programmers we know this better as an xor statement–A is true if and only if B is false, and vice versa–but since there is no colloquial English equivalent of xor, we instinctively infer the meaning from the speakers misstatement.
- As programmers we tend to look at || as a short-circuit operator evaluated left to right. But this English statement defines no explicit evaluation order. This could have been written “I’m either traveling by train or by car” (notice “car” and “train” are reversed), but it means the same thing. In other words, we are evaluating the arguments for truth, not consequence. Thus, order should not affect truth.
Closing Thoughts
In most real-world Ruby contexts these operators will work interchangeably so long as precedence order is considered. But even so, keep in mind that mixing the two styles in different contexts is not necessarily a sign of inconsistency. Using the appropriate operator may actually be a sign of maturity: a way of communicating slightly different semantics in an otherwise logically equivalent context.
7 replies on “Ruby: On The Perl Origins Of “&&” And “||” Versus “and” And “or”.”
Excellent exposition, thank you.
Thanks! I <3 Ruby.
Why is “Iām either traveling by car or by train” a misleading statement in English? It doesn’t imply that both possibilities will be true… I don’t see why you call it a misstatement.
Just read English “or else” for Perlish/Rubish “or”, and the meaning is clear. English has several meanings of “or”, and the sequential meaning is one of them: Funny or die. Put up or shut up.
Analogously, “A and B” means “A, and iff A succeeds, B”. This is the meaning of English “and” in instructions: Add water and stir.
There’s no need for a xor operator as xor is basically the same as != . Naturally there’s no lazy evaluation with xor, as you always need both operands to determine the result.
I would argue that the word “and” in common usage is still ambiguous, though we can say “and then” to imply the logical consequences of A being true. For example, the statement “Please put Alice in the car and [then] take her to day care.” seems to say B iff A, where it is necessary to know A to determine whether or not we should do B. Personally, though, I tend to not say “then”. It’s also interesting that in real life we could have just said B, “Please take Alice to day care.”, and it would be irrelevant if A is true.
The statement “Please pick up the dry cleaning and pick up Alice from day care.”, however, implies that both A and B are true, not necessarily implying order; in other words they could just as well be written as two statement, “Please pick up the dry cleaning. Please pick up Alice from day care.” The use of “and” is only to create a list of items that need to be true, not to imply a relationship between them.
We can easily mix these semantics in sentence like, “Please pick up the dry cleaning and Alice from day care, and make her a peanut butter and jelly sandwich and sliced apple or pear.” Despite several logically ambiguities I’d bet we’ll all mentally parse the semantics essentially the same way. We know that if the dry cleaners is closed we still need to pick up Alice, that a peanut butter and jelly sandwich is a single item and not “(peanut butter) and (jelly sandwich)”, that Alice should have some fruit even if we can’t make a sandwich, and if Alice wants both apple and pear that’s probably ok. (In others words it’s not necessarily an xor: we’re ambiguous.)
Sorry… Not trying to dwell on idiosyncrasies, just pointing out some of the inferences we make in English. š
I’m sorry, but your article is a little misleading.
actually, perl’s “or” and “and” and ruby ones are a little different beasts, though intendend to be used in a similiar circuimstances
Perl operators work much the same as && and ||, albeit with much lower precedence. “and” has higher precendence than “or”. So, for expressions with simple “boolean”s (should quote that word for Perl) && and ||, and “and” and “or are more or less interchangeable.
but in ruby “and” and “or” are on the same precedence level!
so, perl’s
func1 or func2 and func3
is equivalent of
func1 or (func2 and func3)
and won’t call both func2 and func3 if func1 is “true”
while in ruby this would be equivalent of
(func1 or func2) and func3
and won’t call func2, but WILL call func3 if func1 is true
subtile enough to NOT recommend using “and” and “or” in ruby at all, unless you really know what you’re doing. postfix “if” and “unless” are better for control flow.
(Sorry to bump this old thread, but that last comment should not be left for posterity here…)
@codesnik Bash programmers have no problem with the Ruby “and” and “or”, since in both languages their precedence is equal.
Your argument to not use “and” and “or” in Ruby “at all” is way too strong, based on too fine a point, since you would be crazy to suggest not using “&&” and “||” operators in Bash.
When needed to produce more concise yet readable code, “and” and “or” in Ruby is just plain good. Anyone calling himself a Ruby expert cannot ignore them.