In ruby, and is the same as &&, but why does and have lower precedence?
false and false || true # => false
false && false || true # => true
You're absolutely correct that the humanised operators have lower precedence. There is an excellent (and brief!) article on this here if you want more information.
Simplest answer (from that article):
Properly understood, and and or are control flow operators, not boolean operators.
Related
I am using a tutorial, and it has a conditional like this:
if Restaurant.method1
puts "XXX"
elsif Restaurant.method2
puts "YYY"
end
Both methods return a Boolean value of true or false. Similarly, for variables, I have seen something similar:
if x
puts "XXX"
else
puts "YYY"
end
I am wondering what exactly are you checking for considering that there is no equality operator (==) or assignment operator (=)? There must be some sort of equality check that perhaps hidden by the simplistic nature of Ruby, because I'm thinking this logically in my head and "If x", and "If Restaurant.method" both don't really make any sense as a conditional without some sort of check.
This is a common paradigm in programming, not a Ruby abstraction. You are checking if something is truthy. In ruby in particular, everything is truthy except false and nil. Try it yourself in your console if you want to test this:
!!1 # => true
!!0 # => true
!![] # => true
!!{} # => true
...etc, whereas
!!false # => false
!!nil # => false
Important note: this is only the case for Ruby. Other languages have different rules. For example, in some languages 0 is falsy. It's important to learn these early on when learning a new language.
Ruby has "truthy" statements. That means multiple things can evaluate to true. Everything in Ruby is true except nil and false.
Are not and ! synonyms, or are they evaluated differently?
They are almost synonymous, but not quite. The difference is that ! has a higher precedence than not, much like && and || are of higher precedence than and and or.
! has the highest precedence of all operators, and not one of the lowest, you can find the full table at the Ruby docs.
As an example, consider:
!true && false
=> false
not true && false
=> true
In the first example, ! has the highest precedence, so you're effectively saying false && false.
In the second example, not has a lower precedence than true && false, so this "switched" the false from true && false to true.
The general guideline seems to be that you should stick to !, unless you have a specific reason to use not. ! in Ruby behaves the same as most other languages, and is "less surprising" than not.
An easy way to understand the not operator is by looking at not true && false as being equivalent to !(true && false)
I have an RSpec-driven example here: Ruby's not keyword is not not but ! (not)
In essence:
They differ in precedence
They are not aliases
! can be overriden, whereas not cannot be overriden
when you override ! then not will be overriden too, hence it must be using ! under the hood
My understanding is that in the Ruby programming language, only nil and false are considered false, and EVERYTHING else is considered true.
Thus, 1 == true SHOULD return true.
I was working on a Rails 4.0.2 project using MS SQL Server (boolean field, tinyint(1)) and couldn't get the boolean working properly. The value in the DB column was 1.
Stumped, I started testing some things in the console. Here's what I got in my Rails console:
1 == true # => false
0 == true # => false
"test" == true # => false
"" == true # => false
Why is everything registering as false? I thought they were all supposed to be true?
I ended up having to do my boolean check via <attribute>.to_i == 1 to get a valid true/false value.
Am I missing something in the Ruby language or was it updated in some version I wasn't aware of? I'm using RVM, ruby 2.0.0p481 (2014-05-08 revision 45883) on a Mac machine.
Updated: 2014-10-28 09:00
After reading the excellent answers below, I understand where my thinking was wrong.
I think one of the problems is that most of the DB adapters I use (PostgreSQL, MySQL, etc...) converted boolean values in the DB for me.
For instance, in a lot of my code bases I have:
# User has an :admin boolean attribute
class User < ActiveRecord::Base
def admin?
admin == true
end
end
And I suspect this works "fine" because the DB adapter takes care of converting the DB value to a proper boolean for me.
However, I'm currently work on a project where I'm required to use MS SQL Server, and I've run into many "gotchas" with the DB adapter, one of which is I don't believe it treats boolean fields the same as the other adapters do.
Thus, I always considered any TRUTHY value to be equal to true, which it is not. I guess that's why rspec and others have moved to use be_truthy in their own syntax instead of purely be_true.
I'm just surprised it took me a few years before I ran into a problem like this!
My understanding is that in the Ruby programming language, only nil and false are considered false, and EVERYTHING else is considered true
This is true.
However,
"Thus, 1 == true SHOULD return true."
is false.
Explanation: in Ruby everything except false/nil is considered true. However when testing for equality, like x == true you're actually not testing "is this value considered true" but "is this value equal to true".
And of course 1 isn't equal to true, 1 is a number and true is a boolean value. You can read a very good blog post about equality in Ruby at "Ruby Equality And Object Comparison".
If you really, really want to test it that way, you need to convert the expression like 1 to its boolean value, which you can do by double negating it. So !!1 # => true.
So, your examples will look like this:
!!1 == true # => true
!!0 == true # => true
!!"test" == true # => true
!!"" == true # => true
However I believe it isn't necessary in most cases.
When working with MSSQL you should let Active Record do all the conversions for you. Declare the field in a migration, with type boolean, and when you do your where search in the database, do it like this:
Model.where(['attribute = ?', true])
Model.where(:attribute=> true)
This way ActiveRecord will do all the work related to converting the type to a database compatible one for you.
In terms of logical predicates every object besides nil and false are TRUTHY. What basically means that statement corresponding our predicate (condition) will be executed.
While nil and false are FALSEY predicate.
In practice it means:
if predicate
statement_a
else
statement_b
end
Whatever is not a predicate, except nil and false statement_a will be executed. Otherwise statement_b will get the jack pot.
First off, your assumption that everything in Ruby that isn't false or nil is considered true, is true.
Let's take each of your four examples:
1 == true # => false
When evaluating this expression, Ruby takes the class of the first argument, looks for the operator method and evaluates. So, for Fixnums, it evaluates whether or not 1 is equal to another Numeric number. Fixnum#== docs that is equivalent to 1.
0 == true # => false
Same as above.
"test" == true # => false
This is doing an equality test through the String class. As stated in the String#== docs, the class is tested on the right side and if it isn't a string, but responsed to to_str (true does), then the Object#=== method is used and the evaluation asks if the two are the same object, which is not the case here.
"" == true # => false
This is the same as above.
Esse's answer is correct in showing that all objects other than false and nil are true.
!!false # => false
!!nil # => false
The == is a method just like any other method in Ruby that a class uses to decide whether the passed parameter (the parameter on the right side) is equal to its object or not, just like you can define your own == method for your classes. In fact you could even modify the way == methods works for any Ruby basic object such as Fixnum if you wish.
So when you say 1 == true what you are actually saying is 1.==(true) in which case the class Fixnum doesn't like to consider the passed parameter true to be equal to its object 1.
Now when you say everything in Ruby except nil and false are considered true, the correct statement is that in Ruby only false and nil are falsey and everything else is truthy. So when Ruby has to decide whether a value or object count as or evaluates as true (such as in an if statement: if ('test')), it determines whether it is truthy or falsey, but not whether (object).==(true) returns true or false
This question already has answers here:
Difference between "and" and && in Ruby?
(8 answers)
Closed 3 years ago.
What's the difference between the or and || operators in Ruby? Or is it just preference?
It's a matter of operator precedence.
|| has a higher precedence than or.
So, in between the two you have other operators including ternary (? :) and assignment (=) so which one you choose can affect the outcome of statements.
Here's a ruby operator precedence table.
See this question for another example using and/&&.
Also, be aware of some nasty things that could happen:
a = false || true #=> true
a #=> true
a = false or true #=> true
a #=> false
Both of the previous two statements evaluate to true, but the second sets a to false since = precedence is lower than || but higher than or.
As the others have already explained, the only difference is the precedence. However, I would like to point out that there are actually two differences between the two:
and, or and not have much lower precedence than &&, || and !
and and or have the same precedence, while && has higher precedence than ||
In general, it is good style to avoid the use of and, or and not and use &&, || and ! instead. (The Rails core developers, for example, reject patches which use the keyword forms instead of the operator forms.)
The reason why they exist at all, is not for boolean formulae but for control flow. They made their way into Ruby via Perl's well-known do_this or do_that idiom, where do_this returns false or nil if there is an error and only then is do_that executed instead. (Analogous, there is also the do_this and then_do_that idiom.)
Examples:
download_file_via_fast_connection or download_via_slow_connection
download_latest_currency_rates and store_them_in_the_cache
Sometimes, this can make control flow a little bit more fluent than using if or unless.
It's easy to see why in this case the operators have the "wrong" (i.e. identical) precedence: they never show up together in the same expression anyway. And when they do show up together, you generally want them to be evaluated simply left-to-right.
and/or are for control flow.
Ruby will not allow this as valid syntax:
false || raise "Error"
However this is valid:
false or raise "Error"
You can make the first work, with () but using or is the correct method.
false || (raise "Error")
puts false or true --> prints: false
puts false || true --> prints: true
The way I use these operators:
||, && are for boolean logic. or, and are for control flow. E.g.
do_smth if may_be || may_be -- we evaluate the condition here
do_smth or do_smth_else -- we define the workflow, which is equivalent to
do_smth_else unless do_smth
to give a simple example:
> puts "a" && "b"
b
> puts 'a' and 'b'
a
A well-known idiom in Rails is render and return. It's a shortcut for saying return if render, while render && return won't work. See "Avoiding Double Render Errors" in the Rails documentation for more information.
or is NOT the same as ||. Use only || operator instead of the or operator.
Here are some reasons. The:
or operator has a lower precedence than ||.
or has a lower precedence than the = assignment operator.
and and or have the same precedence, while && has a higher precedence than ||.
Both or and || evaluate to true if either operand is true. They evaluate their second operand only if the first is false.
As with and, the only difference between or and || is their precedence.
Just to make life interesting, and and or have the same precedence, while && has a higher precedence than ||.
Just to add to mopoke's answer, it's also a matter of semantics. or is considered to be a good practice because it reads much better than ||.
Does Ruby have a plain-English keyword for exclusive or, like they have "and" and "or"? If not, is this because exclusive or doesn't allow evaluation short-cutting?
No it doesn't, you can only use ^.
Don't know why there isn't particularly, may just be because it isn't as commonly used.
I ran into an issue because the '^' operator acts bitwise on numbers,
true ^ 1
=> false
1 ^ true
TypeError: can't convert true into Integer
true ^ 1
so my workaround was:
( !!a ^ !!b ) where the double-bang coerces them into booleans.
!!1 ^ !!true
=> false
!!1 ^ !!false
=> true
Firstly, I don't think shortcircuiting can sensibly apply to XOR: whatever the value of the first operand, the second needs to be examined.
Secondly, and, &&, or and || use shortcircuiting in all cases; the only difference between the "word" and "symbol" versions is precedence. I believe that and and or are present to provide the same function as perl has in lines like
process_without_error or die
I think the reason for not having a xor named function is probably that there's no point in a low-precedence operator in this case and that it's already a confusing enough situation!
Try ^
true ^ false #=> true
true ^ true #=> false
false ^ false #=> false
No plain english equivalent operator though.
As an alternative to Matt Van Horn's double negation trick for using XOR on arbitrary types, you can chain another XOR test, starting with nil. i.e.:
!!foo ^ !!bar
is equivalent to
nil ^ foo ^ bar
This looks neater to my eye, and I suppose requires one less logical operation
Any implementation of xor won't allow short circuiting. Both expressions need to be evaluated no matter what.
Ruby does provide the ^ operator, but this will choke on truthy values. I've implemented a function to handle the cases where I want an xor that behaves more like and and or:
def xor(a,b)
(a and (not b)) or ((not a) and b)
end
Unlike ^, this function can be used in situations similar to the following:
xor("hello".match(/llo/), false) # => true
xor(nil, 1239) # => true
xor("cupcake", false) # => false
John's answer appears incorrect. In irb with 1.9.3, xor("cupcake", false) returns true, as you'd expect.
1.9.3-p429 :104 > def xor(a,b)
1.9.3-p429 :105?> (a and (not b)) or ((not a) and b)
1.9.3-p429 :106?> end
=> nil
1.9.3-p429 :107 > xor(false, true)
=> true
1.9.3-p429 :108 > xor("cupcake", false)
=> true