Reputation: 16202
The single pipe "or" |
exists as a method on TrueClass
and FalseClass
, but the short circuit ||
operator does not. Neither does it exist as a method on Object
.
This seems to be an exception to ruby's "everything is an object" metaphor.
Main Question: Syntactically speaking, what are ||
and &&
? Are they just baked bits of global syntax?
Secondary Question: I'm flagging this as not part of the main question, because it is potentially subjective, though I suspect it probably isn't.
Is there a language design or performance reason for this asymmetry? It seems to me both operators could have been implemented as methods on Object
. Something like:
class Object
def short_circuit_or(other)
!nil? ? true :
!other.nil? ? true : false
end
end
I assume there is a reason they were not. What is it?
Upvotes: 2
Views: 251
Reputation: 72177
Both |
and ||
are operators. ||
is part of the language while |
is implemented as a method by some classes (Array
, FalseClass
, Integer
, NilClass
and TrueClass
) .
In programming languages, |
is used in general as the bitwise OR operator. It combines the bits of its integer operands and produces a new integer value. When used with non-integer operands, some languages convert them to integer, others prohibit such usage.
||
is the logical OR operator. It combines two boolean values (true
or false
) and produces another boolean value. When its operands are not boolean values, they are converted to boolean by some languages. Ruby (and JavaScript and other languages) evaluate its first operand as boolean and the value of the expression is the value of its first operand if its boolean value is true
or the value of its second operand if the logical value of its first one is false
. The type of the resulting value is its original type, it is not converted to boolean.
Each language uses its own rules to decide what non-boolean values are converted to false
(usually the number 0
, the empty string ''
and null
or undefined
); all the other values are converted to true
. The only "false" values in Ruby are false
(boolean) and nil
(non-boolean); all the other values (including 0
) are "true".
Because true || anything
is true
and false && anything
is false
, many programming languages including Ruby implement short-circuit evaluation for logical expressions.
Using short-circuit evaluation, a logical expression is evaluated from left to right, one operand at a time until the value of the expression can be computed without the need to compute the other operands. In the examples above, the value of anything
doesn't change the value of the entire expression. Using short-circuit evaluation, the value of anything
is not computed at all because it does not influence the value of the entire expression. Being anything
a method call that takes considerable time to execute, the short-circuit evaluation avoids calling it and saves execution time.
As others already mentioned in comments to the question, implementing ||
as a method of some class is not possible. The value of its second operand must be evaluated in order to be passed as argument to the method and this breaks the short-circuiting behaviour.
The usual representation of the logical values in programming languages uses only one bit (and I guess Ruby does the same.) Results of |
and ||
are the same for operands stored on one bit.
Ruby uses the |
symbol to implement different flavors of the OR
operation as follows:
nil
;An expression like:
x = false | a | b | c
ensures that all a
, b
and c
expressions are evaluated (no short-circuit) and the value of x
is the logical OR of the logical values of a
, b
and c
.
If a
, b
and c
are method calls, to achieve the same result using the logical OR operator (||
) the code needs to look like this:
aa = a
bb = b
cc = c
x = aa || bb || cc
This way each method is called no matter what values are returned by the methods called before it.
For TrueClass
, FalseClass
and NilClass
, the |
operator is useful when short-circuit evaluation is not desired.
Also, for Array
(an array is just an ordered set), the |
operator implements union, an operation that is the semantically equivalent of logical OR for sets.
Upvotes: 4