[Ruby] Boolean values ​​and logical operators

Introduction

Here's a quick summary of Ruby's boolean values ​​and points that are often overlooked by logical operators.

Please take a look to the end.

Target audience

--People who started learning Ruby --People who have just started programming --People who do not understand the calculation of expressions using boolean values ​​and logical operators

Contents of this article

1. Ruby truth value 2. Points that are often forgotten in conditional branching (if and unless) 3. Return value of expression including logical operator 4. Summary 5. Finally 6. Reference site

1. About Ruby truth value

Ruby booleans have the following rules.

- false and nil are judged as ** "false" ** - All other values ​​are judged as ** "true" **

#All values ​​and true itself are true
1
2
3
[1, 2, 3]
'apple'
''
true

#false and nil are false
false
nil

And I often write actual code by taking advantage of these properties.

#When writing without being aware of the truth rule
if foo == true
  # ...
end

if bar == false
  # ...
end

if baz == nil
  # ...
end

#When writing with the truth rule in mind
if foo
  # ...
end

unless bar
  # ...
end

unless baz
  # ...
end

Of course, the latter code has been refactored and is considered clean code.

2. Points that are often forgotten about conditional bifurcation (if and unless)

Next, I will explain the points that are often forgotten when making statements about conditional bifurcation.

The return value is the value of the last evaluated expression

The first is about ** return value ** .

In Ruby, ** if and unless statements return the value of the last evaluated expression as a return value. ** **

It's hard to understand what this means, so let's think about it while looking at the actual code.

Consider running the following code on irb.

#When writing without being aware of the return value
num = 2

if num.odd? 
  puts 'Is odd'
else 
  puts 'Is an even number'
end
#=>Is an even number

#When writing with the return value in mind
num = 2

if num.odd?
  'Is odd'
else
#The if statement returns the value of this formula as a return value
  'Is an even number'
end
#=>Is an even number

In the latter case, num is not odd, so the first condition is not met and the second condition is met.

Then, ** returns the value of the expression included in the processing contents under the matched conditions as the return value of the entire if statement. ** **

In other words, when executing with irb etc., you can check which condition was executed by looking at the return value of the if statement without using ** puts ** like the former . ..

Postfix if

The next point that is often forgotten is ** postfix if **.

As the name suggests, the postfix if is ** to put the if statement at the beginning of the sentence after the sentence **.

#When not using postfix if
# (nil?Is a method that returns true if the object is nil)
if user.nil?
  redeirect_to :root
end

#When using a postfix if
redirect_to :root if user.nil?

This allows you to reduce the number of lines and ** keep your code simple. ** **

However, as a caveat, if you try to return the evaluation result as a return value, ** the result different from the expected result is often returned. There is. ** **

def greeting(country)
  #If country is not specified,"Hello"I want to return
  'Hello'
  #country'japan'Then"Hello"I want to return
  'Hello' if country == 'japan'
end
greeting('japan') #=> "Hello"
greeting('us') #=> nil

This is, if the condition statement of ** post-if it was false, processing of the previous if has a mechanism that returns nil without evaluating the (in this case, 'Hello') Because. ** **

Therefore, the postfix if is not used indiscriminately.

-** Used in combination with the early return described below ** -** Treat as a statement, not an expression (do not write processing using the return value) **

It is better and safer to use in such cases.

Use early return

In conditional branch statements, it is common practice to return immediately when the condition is met so that it does not affect the back.

This is called ** early return ** and is often used to avoid ** rare cases or deep nesting of conditional statements. ** **

def greeting(country)
  #If country is nil, return a message and exit the method
  return 'Please enter country' if country.nil?
  
  #country'japan'If'Hello'And exit the method
  return 'Hello' if country == 'japan'
  #Otherwise'hello'Returns
  'Hello'
end
greeting(nil)     #=> "Please enter country"
greeting('japan') #=> "Hello"
greeting('us')    #=> "Hello"

3. Return value of an expression containing logical operators

Finally, I will explain the points that are often overlooked with expressions that use logical operators.

&&Or||Return value and timing of the end of evaluation

Logical operator&&Or||Care must be taken regarding the return value of the formula when using.

See the results below.

#Example 1
'apple' && 'banana' && 'grape' #=> "grape" 
#Example 2
'apple' && nil && 'grape'      #=> nil
'apple' && false && 'grape'    #=> false

#Example 3
nil || false                        #=> false
false || nil                        #=> nil
nil || false || 'apple' || 'banana' #=> 'apple'

As you can see, it is not necessarily ** true or false **.

** This is related to Ruby evaluating expressions from the left side until it is determined that the whole expression is true or false. ** **

Then, when the truth or falseness of the entire expression is confirmed, the evaluation of the expression is completed, and the value of the last evaluated expression is returned.

for that reason

-** In case of Example 1 **

Since all expressions had to be evaluated, ** 'grape' ** of the last expression is returned as the return value.

-** In case of Example 2 **

When the second nil was evaluated , it was decided that the boolean value of the entire expression was false , so the evaluation was finished at that point and ** < code> Returns the last nil **. The same is true for false

-** In case of Example 3 **

||The idea is the same in the case of, for example, in the case of the first line, since the truth value of the entire expression was fixed at the last point, it is the value of the last expression.**false**Is returned as a return value. The same applies to the second line.

Also, in the case of the third line, the return value is'apple' because the boolean value of the entire expression was determined when the expression 'apple' was reached.


As a further point to note, in the case of if statements, you do not have to be so conscious,In situations other than if statements&&Or||When intentionally usingThere is also.

Therefore, if you see these logical operators, be careful to see if they are used as described above.

Control flow using and and or

Finally above&&、||There are and and or as operators that work in the same way as, but I will briefly touch on how they are used.

and and or are basically&&When||When同じですが、いくつかの場面において違った結果を返すこWhenがあります。

This is related to ** operator precedence **.

image.png

It looks like the figure above, and and or**&&When||よりも優先順位が低いWhenいう状態になっています。**

For example, suppose you write the following code.

t1 = true
t2 = false
f1 = false

t1 || t2 && f1 #=> true
t1 or t2 and f1 #=> false

In this case, this is the same as writing the following code.

# &&Is||Higher priority than
t1 || (t2 && f1)
#Since the priority of and and or is the same, they are evaluated in order from the left.
(t1 or t2) and f1

From these as welland and or&&When||Whenは完全に同じようには扱えないWhenいうこWhenがわかります。

Furthermore, and and or, which have such characteristics, are not often used in conditional branching, and are suitable for handling ** control flows. ** **

def greeting(country)
  #If country is nil or false, return a message and exit the method
  country or return 'Please enter country'

  return 'Hello' if country == 'japan'
  'hello'
end

greeting(nil)     #=> "Please enter country" 
greeting('japan') #=> "Hello"
greeting('us')    #=> "hello"

The above code realizes the control flow ** that says ** "Is A true? If it is not true, do B". In such a case, and and or are used. ..

4. Summary

--Ruby booleans are false and nil are ** "false" **, and all other values ​​are ** "true" **.

--In Ruby, the return value of the if statement is ** the value of the last evaluated expression ** --By using a postfix if statement, ** simple code can be applied ** --Early return is used to avoid ** rare cases and deep nesting of conditional statements ** . --In Ruby, ** evaluate the expression in order from the left side until it is determined that the entire expression is true or false, and ** evaluate the expression when the boolean value of the entire expression is determined. Returns the value of the last evaluated expression as the return value ** -and and or&&When||than**Low priority, often used in control flow**

5. Finally

I hope the content of this article will be helpful to you.

Thank you for watching until the end.

6. References

Ruby Reference Manual: Control Structure [Ruby] What is the return value of the method with the trailing if ...? Is it a bad idea to use return for the return value of a Ruby method Ruby's "postfix if" returns "if evaluation" Early return with ruby How to write conditional branch simply using return in Ruby [[For beginners] Idioms and useful methods that can be used for refactoring in Ruby and Rails](https://qiita.com/jnchito/items/dedb3b889ab226933ccf#%E4%BB%A3%E5%85%A5%E3% 81% 97% E3% 81% A6% E3% 81% 8B% E3% 82% 89if% E3% 81% A7% E5% AD% 98% E5% 9C% A8% E3% 82% 92% E7% A2% BA% E8% AA% 8D% E3% 82% 92% E3% 81% BE% E3% 81% A8% E3% 82% 81% E3% 81% A6% E6% 9B% B8% E3% 81% 8F) Book: Introduction to Ruby for Professionals

Recommended Posts