Apart from the priority of the operands, this behaviour is the result of the short-circuit evaluation of logic operators.
When evauating and
, if the first operand is found to be false, then there is no reason to evaluate the second. The value of a and b
is therefore calculated as a ? b : a
.
Likewise, the or
operator contracts to a ? a : b
.
These optimisations work fine logically, when we don't care about the specific value returned but only whether it is true or false. But it also allows for useful coding idioms, such as
( list = list || [] ) << item
which works because list = list || []
is evaluated as list = list
(a no-op) if list
is true (non-nil), or list = []
(creating a new empty array) if list
has already been initialised, and so is "true".
So an expression like 2 and (c = 3)
evaluates to 2 and 3
or 2 ? 3 : 2
, so 3
.