Ruby && Operator on Integers

Working on | | and && operators

Boolean operators in ruby are short-circuiting: if it is possible to determine the value of the expression from the left-hand argument, the right-hand argument isn't evaluated.

Therefore, a simpler mental model for evaluation of a boolean expression involving && is to consider first expressions involving only two operands: the left-hand operand is evaluated first; if the value of this operand is nil or false, the operand is returned and the right-hand operand isn't evaluated; if the left-hand operand is anything else, the right-hand operator is evaluated and its value is returned.

From this definition, it's clear that, as you note, expressions involving boolean operators don't return true or false, but simply a true value or a false value. It's worth noting that this doesn't make any difference in a context where a boolean expression is used only for its true-ness or false-ness.

Hope it will help you.

Ruby's && operator

There's several aspects here.

Why does ruby returns the value of the last statement (when the first is true and the second one is also true) and does not return a boolean?

Because it is more useful this way. This semantics is in fact so useful that PHP 7 added it (but as a new operator, ??). In Ruby, just as in PHP, all values are truthy or falsy. Unlike PHP, Ruby has a much stricter idea about it: only false and nil are falsy, everything else is truthy. This allows you to easily give defaults:

name = options[:name] || "John Doe"

If options[:name] is not found and returns nil, then that part is falsy and the right side of || will be returned; otherwise, options[:name] will be returned.

In most cases you don't need a boolean, because truthiness or falsiness suffices. If you really really want to have a boolean, for example in order not to leak private information out of a class, the idiom !!value is common:

def has_name?
!!(self.name || self.nickname)
end

The result of ! (negation) is always boolean; if you negate twice, you will convert truthiness to true and falsiness to false.

Finally,

The thing that bugs me is the condition in the while - while a_next = a.next && b_next = b.next - written like this, it always sets a_next = b_next (the first question seems related to this behavior, I think). But when i wrap the two && operands - it works as expected - (a_next = a.next) && (b_next = b.next) # works ok.

Then you need to wrap them. That's due to operator precedence, and works like this by design, because it is more normal to write

blue_green = colour == :blue || colour == :green

than

blue_green = (colour == :blue || colour == :green)

There is another set of boolean operators that are actually designed to work like you propose, the only difference being the precedence, so you could write this and have it work:

while a_next = a.next and b_next = b.next

It is identical to

while (a_next = a.next) && (b_next = b.next)

A warning though: using and and or operators instead of && and || improperly is a common enough mistake that many style guides outright ban them (they are useful only in this context - assignment inside loop conditions - and it can be solved with parentheses instead). E.g.:

The and and or keywords are banned. It's just not worth it. Always use && and || instead.

What is the difference between '&&' and '&' in Ruby

&& is a boolean and. It returns the second argument if the first argument is true-ish. Because 0 is true-ish in Ruby, 1 is returned.

& is a bitwise and. It compares the bit representation of the values. Because (imaging 8 bit) 00000000 (0) and 00000001 (1) have no 1 digits in common, 00000000 (0) is returned.

|| and && aren't methods on Object -- what are they?

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:

  • bitwise OR for integers;
  • non-short-circuit logical OR for booleans and nil;
  • union for arrays.

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.

Operators && and || are objects in ruby?

It depends on how you define "everything". I personally would never claim that each individual concept in ruby is an object. I suppose there isn't really a good definition to describe how ruby works. I think you just have to accept the way ruby does it, which will become plain as you use it.

If you want to see if something is an object, try assigning it to a variable, or calling a method on it. You'll get an error if you try to do that with an operator. A notable exception is methods, which aren't objects but return objects.

Note that the concept of an object is somewhat abstract. Two variables can point to the same object. Every object is represented by an object_id. You might think of an object_id like a location in memory. Or, you can think of an object as a house, and multiple address books can contain the house's address.

# point 2 variables to the same object
>> s = t = 's'
=> "s"
>> s.object_id
=> 70269794388360
>> t.object_id
=> 70269794388360

# get the object by id (for demonstration only; I don't recommend using this in application code)
>> ObjectSpace._id2ref(70269794388360)
=> "s"

# modifying the object. both variables "see" the change
>> s << '_'
=> "s_"
>> t
=> "s_"

Continuing the house analogy, appending to a string via << is like bringing a new chair into the house. Everyone who follows their address book to that house (using the address) will see that the house (object) has the new chair.

The ruby language designers did not see a reason to allow treating operators like && as objects. Can you see any reason to allow it?

Operator precedence for And/&& in Ruby

I don't quite understand the question you are asking. I mean, you have already given the answer yourself, before even asking the question: && binds tighter than = while and binds less tightly than =.

So, in the first case, the expression is evaluated as follows:

( a=f(2) )  and  ( b=f(4) )
( a= 2 ) and ( b=f(4) )
2 and ( b=f(4) ) # a=2
2 and ( b= 4 ) # a=2
2 and 4 # a=2; b=4
4 # a=2; b=4

In the second case, the evaluation is as follows:

a   =   (  f(2) && ( b=f(4) )  )
a = ( 2 && ( b=f(4) ) )
a = ( 2 && ( b= 4 ) )
a = ( 2 && 4 ) # b=4
a = 4 # b=4
4 # b=4; a=4

Undefined method = for false when comparing integers

So why is it erroring?

This is not because ! is a method and you need to call it with parentheses. This is due to operator precedence or order of operations

In Ruby, all integers evaluate to true, the only values that are evaluated to false are false and nil, per the documentation. Now, let's look at your condition:

if !ARG.length <= 2

In this example, ! is the NOT operator. Performing this operation implicitly coerces it into a boolean for boolean operation. And since, as mentioned earlier, ARGV.length is an integer, it is evaluated to true, thus !true is false.

! happens first because ! has higher precedence than <=. After !ARGV.length is evaluated, Ruby then reports that you are trying to do comparison on false and an integer, that's illegal. You have to use grouping to control which operations happen when:

if !(ARGV.length <= 2)

The parentheses will tell Ruby to evaluate the condition inside the parentheses first, then continue evaluating, like order of operations. So, the inside is evaluation, then logical NOT happens.

What is wrong with my && operator?

You're probably complicating this a bit more than it needs to be.

2.2.0-preview1 :001 > load 'no_repeat.rb'
=> true

Testing as a string

2.2.0-preview1 :002 > no_repeats?("1981")
=> false
2.2.0-preview1 :003 > no_repeats?("1983")
=> true

Testing as an integer

2.2.0-preview1 :004 > no_repeats?(1981)
=> false
2.2.0-preview1 :005 > no_repeats?(1983)
=> true

and no_repeat.rb looks like

  def no_repeats?(year)
digits = year.to_s.split(//)
digits.size == digits.uniq.size
end

Edit: Benchmarks

Using Original Post

real 0m0.598s
user 0m0.583s
sys 0m0.015s

Using .split(//)

real 0m1.322s
user 0m1.321s
sys 0m0.000s

Using .chars.to_a

real 0m0.562s
user 0m0.557s
sys 0m0.004s

So, in efforts to make this more of a complete answer, I've included my benchmarks, each using the method 400,000 times. By using split(//), you will be taking almost a 2x performance hit. By using chars.to_a instead, you'll be up with your original speeds.

def no_repeats?(year)
digits = year.to_s.chars.to_a
digits.size == digits.uniq.size
end


Related Topics



Leave a reply



Submit