Is There Any Wisdom Behind "And", "Or" Operators in Ruby

Is there any wisdom behind and, or operators in Ruby?

My guess is that's a direct carry-over from Perl. The operators or and and were added later in Perl 5 for specific situations were lower precedence was desired.

For example, in Perl, here we wish that || had lower precedence, so that we could write:

try to perform big long hairy complicated action     || die ;

and be sure that the || was not going to gobble up part of the action. Perl 5 introduced or, a new version of || that has low precedence, for exactly this purpose.

An example in Ruby where you could use or but not ||:

value = possibly_false or raise "foo"

If you used ||, it would be a syntax error.

Ruby: what is the difference between the comparatives: || and or

or the second example all variables are checked and if one is true then it will execute "do something".

This is false sentence.

As a result your assumptions are not correct.

Both or and || do the same thing.

The main difference is that or has lower precedence than ||. So you should pay attention to more complex evaluations:

# Simple cases are not confusing
false || true # true
false or true # true

# This is more complex
a = false || true # a=true
a = false or true # a=false

# Also similarly as 1 + 2*3 returns 7, the following returns true:
false or false||true # true
# BUT! THIS IS IMPORTANT!
a = false or false||true # a=false
a = (false or false||true) # a=true

Here is a list of operators precedence.

So the real difference will be noticed if you use the expression that includes any of the following operators:

  • .. ... - Range (inclusive and exclusive)
  • ? : - Ternary if-then-else
  • = %= { /= -= += |= &= >>= <<= *= &&= ||= **= - Assignment
  • defined? - Check if specified symbol defined
  • not - Logical negation
  • and - Logical composition

there might be others too.

You can thing about the difference between those as different between + and *: ||==* and or=+. The same applies to and and not.

You should really pay attention to that.

Personally I prefer || operator as its semantics is well understood and avoid or.

While it 'feels' like or is more friendly in many cases (see my code sample), even in trivial ones, it is a source of bugs.

Why || and or behaves differently in rails?

The reason that || and or behave differently is because of operator precedence.

Both || and && have higher precedence than the assignment operator and the assignment operator (=) has higher precedence than and/or

So your expressions will actually be evaluated as follows :-

@year = params[:year] || Time.now.year

is evaluated as

@year = ( params[:year] || Time.now.year )

and

@year = params[:year] or Time.now.year

is evaluated as

( @year = params[:year] ) or Time.now.year

If in doubt about precedence rules then use parentheses to make your meaning clear.

i = true and false in Ruby is true?

The operators && and and have different precedence, and = happens to be in between.

irb(main):006:0> i = true and false
=> false
irb(main):007:0> i
=> true
irb(main):008:0> i = true && false
=> false
irb(main):009:0> i
=> false
irb(main):010:0>

The first is read as (i = true) and false, the second as i = (true && false).

Why am I seeing different results for two expressions in Ruby, one uses '&&', other uses 'and' operator?

Because they have different operator precedence.

The first evaluates as:

(print (-1 == -1)) and (myobj.nil?)

It prints true, because -1 == -1, then print returns nil and nil and false is nil.

The second is equivalent to:

print ((-1 == -1) && (myobj.nil?))

It prints (true && false), which is false, then print returns nil.

How should I handle a conditional in Ruby where the test could result in an error?

You can just use the safe navigation operator which was introduced to Ruby in 2.3:

def author_name
author&.name
end

Note that self is not needed in your example.

Or when you are on Ruby on Rails then you might want to use delegate:

delegate :name, to: :author, prefix: true, allow_nil: true

Multiple LIKE and AND operators in RAILS/POSTGRESQL

PostgreSQL has a handy expr op all (array) expression so you can say things like:

where content like all (array['%a%', '%b%', '%c'])

as a short form of:

where content like '%a%'
and content like '%b%'
and content like '%c%'

Also, ActiveRecord will conveniently replace a ? placeholder with a comma-delimited list if you hand it a Ruby array. That lets you say things like:

Word.where('content like all (array[?])', %w[a b c].map { |c| "%#{c}%" })

and:

Word.where('content like all (array[?])', some_other_array.map { |c| "%#{c}%" })

Ruby - Loop IF x times and change condition

input = [
0,0,0,44,754,22,0,632,2,22,0,2,
nil,2,24,nil,666,90909,2,4,6,7,
2,7,3,2,2,7,1,8,6,3,2,19,5,46
]

(1..Float::INFINITY).step(4) do |i|
i = i.to_i # is float here
break Statement if i >= input.size
next if input[i].nil? || !input[i+1].zero?

keyword = Statement =~ /WHERE/ ? 'AND' : 'WHERE'
Statement.sub! "THIS", "#{keyword} #{input[i+7]} #{input[i+8]} THIS"
end
#⇒ "Statement WHERE 2 22 AND 2 AND 666 90909 THIS"

Attempt at understanding the double-dispatch pattern

In single dispatch---what you see in most modern OO languages---a method is dispatched based on the run-time type of a single object. This shows up as the dot operator (in ruby, java, javascript, etc.) or the arrow operator (perl, c++).

# look, ma single dispatch!
# method on obj's run-time type that is called
dentist.work_on(patient)

Double dispatch, then, would be based on the run-time type of two objects. There are a few ways this could look; and on which object should the method live?

# Hmm, this looks weird.
# Is the method in to dentist.class or patient.class?
(dentist, patient).do_dentistry()


# okay, this looks more familiar; the method lives on obj1.class
# This only works in static-typed languages which support double dispatch
# in which you declare the type of the method parameters.
dentist.work_on(patient)

class Dentist
def work_on(Adult patient); ...; end
def work_on(Child patient); ...; end
end

Languages like groovy that have multiple dispatch generalize the second example above; they consider the run-time types of all parameters when choosing which method to run. See for example this blog post about groovy and multiple dispatch.

Most modern OO languages only have single dispatch and the Multiple Dispatch Pattern is an attempt to get the benefits of multiple dispatch into the language. It even works for dynamic languages like ruby. It works by doing single dispatch twice in a row. The first method call will call a method on the second object.

class Dentist
def work_on(patient)
patient.dispatch_work(self)
end
def work_on_adult(patient)
drill_as_hard_as_you_can(patient)
end
def work_on_child(patient)
use_bubble_gum_toothpaste(patient)
give_toothbrush_to(patient)
end
end

class Doctor
def work_on(patient)
patient.dispatch_work(self)
end
def work_on_adult(patient)
do_checkup(patient)
end
def work_on_child(patient)
assure_presence_of(patient.guardian)
ask_questions_to(patient.guardian)
do_checkup(patient)
give_cheap_toy_to(patient)
end
end



class Adult
def dispatch_work(dentist)
dentist.work_on_adult(self)
end
end

class Child
def dispatch_work(dentist)
dentist.work_on_child(self)
end
end

The double dispatch pattern is what I call a low-level pattern because other patterns are built on it. For example, the Visitor pattern relies heavily on the double dispatch pattern.


Update Just saw your gists. Your first gist isn't really doing double dispatch. Sure, you're dispatching twice, but you're not changing the behavior in that second dispatch. To change it to double dispatch I'd do something like this.

class Chicken
def make_dispatch dish
dish.make_with_chicken self
end
end

class Beef
def make_dispatch dish
dish.make_with_beef self
end
end


module Dish
def make meat
meat.make_dispatch self
end
end

class Sandwich
include Dish

def make_with_chicken chicken
puts "Grilled Chicken Sandwich"
end

def make_with_beef beef
puts "Roast Beef Sandwich"
end
end

class Stew
include Dish

def make_with_chicken chicken
puts "Thai curry"
end

def make_with_beef beef
puts "Beef stew"
end
end

class Casserole
include Dish

def make_with_chicken chicken
puts "Chicken Pot Pie--or something"
end

def make_with_beef beef
puts "Shepard's Pie"
end
end

Sandwich.new.make(Chicken.new)
Stew.new.make(Chicken.new)
Casserole.new.make(Beef.new)


Related Topics



Leave a reply



Submit