Ruby - unexpected behaviour when using && - ruby

When I write the following line:
if (collection.respond_to? :each && collection.respond_to? :to_ary)
my IDE (Aptana Studio 3) gives me the following error: , unexpected tSYMBEG
however the error goes away if I add brackets:
if ((collection.respond_to? :each) && (collection.respond_to? :to_ary))
or change && to and:
if (collection.respond_to? :each and collection.respond_to? :to_ary)
Any ideas why this is happening? Also what is the difference between && and and?
Thanks

&& has a high precedence (stronger than and, stronger than =).
foo = 3 and 5 # sets foo = 3
foo = 3 && 5 # sets foo = true
It's also stronger than an ambiguous function call. Your code is parsed as such
if (collection.respond_to? :each && collection.respond_to? :to_ary)
if (collection.respond_to? (:each && collection.respond_to?) :to_ary)
which doesn't make any sense. While using and is parsed as such
if (collection.respond_to? :each and collection.respond_to? :to_ary)
if (collection.respond_to?(:each) and collection.respond_to?(:to_ary))
I recommend that you use this one (as it doesn't rely on operator precedence rules and uses the least braces, has shortest brace-distances, and uses and which are more often to be found in if conditions than &&):
if collection.respond_to?(:each) and collection.respond_to?(:to_ary)

Because Ruby is a dynamic language ruby has no way of knowing if you are using the symbols as integers (in which the are stored), and thus the '&&' operator has precedens over function calls, thus you are actually calling
collection.respond_to? (:each && collection.respond_to? :to_ary)
instead of calling
(collection.respond_to? :each) and (collection.respond_to? :to_ary)
which is to method
calls then an boolean logic operator.
When using 'and' instead of &&, 'and' has much lower precedens (lower than function calls) and thus it also works.
'and' and 'or' vs '&&' '||'

Related

Ruby `&&` vs `and` in a block [duplicate]

This question already has answers here:
Difference between "and" and && in Ruby?
(8 answers)
Closed 6 years ago.
In the code below, if I replace the and in the any? statement with &&, it throws an error unexpected tIDENTIFIER, expecting '}'.
def ArrayAddition(arr)
i = 2
until i == arr.length
combinations = arr.permutation(i).to_a
return true if combinations.any?{|array| array.inject(&:+) == arr.max and !array.include? arr.max}
i+=1
end
false
end
What is going on here? Does Ruby handle these operators differently?
The operators and and && have different precedence, and are not equivalent. As such, the Ruby Style Guide advises against using and and or operators: The and and or keywords are banned. It's just not worth it. Always use && and || instead.
Due to the difference in precedence, the other operators in the expression have higher or lower comparative precedence. In this case, the argument for the Array#include? call end up binding to the wrong expression.
You can solve this by adding parentheses around the argument to the Array#include? call.
Yes. and has lower precedence than && (and almost everything else). This expression:
foo and bar baz
...is parsed like this:
foo and (bar baz)
...so Ruby knows foo is a method name (because it can't be anything else). On the other hand, this expression:
foo && bar baz
...is parsed like this:
(foo && bar) baz
...which just doesn't make sense and you get a syntax error.
Generally speaking you should use && unless you specifically want and's lower precedence, so in this case the easiest fix to the syntax error is to use parentheses around the method argument:
foo && bar(baz)
...and so:
array.inject(&:+) == arr.max && !array.include?(arr.max)
As a bonus, this is more readable as well.

Precedence of and/or versus method arguments in ruby

Here are two tests:
if [1,2,3,4].include? 2 && nil.nil?
puts :hello
end
#=>
and
if [1,2,3,4].include?(2) && nil.nil?
puts :hello
end
#=> hello
The above tells me that && has higher precedence than method arguments so it logically ands 2 && nil.nil? which is true and passes that as an argument to include?.
However, there is this test:
if [1,2,3,4].include? 2 and nil.nil?
puts :hello
end
#=> hello
So this is telling me that method arguments and 'and' have the same precedence (or method args are higher than 'and') since it passed 2 to include? before it processed 'and'.
Note: I understand that && and and have different precedence. The question is not regarding this but regarding and or or vs the arguments to a ruby method.
I can't find documentation that affirms this. For instances, this doesn't mention method arguments at all: http://phrogz.net/programmingruby/language.html#table_18.4 or http://romhack.wikia.com/wiki/Ruby_operators.
Could anyone explain this behavior? Namely in that how does ruby know to pass values as arguments to a method vs. process operators?
As you said && and and have different precedence, however the explanation for the following example:
if [1,2,3,4].include? 2 and nil.nil?
puts :hello
end
#=> hello
is the binding strenght of the and as you can read here:
Difference between "and" and && in Ruby?
This basically explains that 2 and nil.nil? will be evaluated as nil, however it will return 2 as can be seen in this example:
foo = :foo
bar = nil
a = foo and bar
# => nil
a
# => :foo
a = foo && bar
# => nil
a
# => nil
I've never seen any documentation about method argument precedence, but one rule of thumb I use when seeing method arguments is to mentally strip the whitespace wherever possible in the arguments and still have the same expression. This normally gives me the precedence:
[1,2,3,4].include? 2&&nil.nil? is the same expression, but you cannot strip the whitespace in
[1,2,3,4].include? 2 and nil.nil? and therefore, the precedence is left to right ... I.e. Method argument is 2.
Anyway, the better question is why on earth would you write statements like this?
Omitting method parenthesis is only useful for code readability. However, your statements are hardly readable and makes one pause over the code and think about it more than he should. If I was to review code like this, I would definitely fail the code review due to poor readability.
In fact, many style guides explicitly state that most methods with arguments should be parenthesized (is this even a word ;). For example:
Ruby style guide

Why does Ruby expression with double ampersand using a return statement cause a syntax error

def foo
true && return false
end
def bar
true and return false
end
foo method causes a syntax error. bar doesn't. Why?
Assuming I want to evaluate one-liners with a return statement (similar to a certain commonly used shell/bash expression), would this be a recommended way to do it, or is there a more recommended approach?
By operator associativity strength,
true && return false
evaluates to
(true && return) false
of which
true && return
is valid, but the false after it is invalid. You cannot have two statements lined up without anything in between.
Side Note
It is worth noting that and and && are not equivalent.
and is a flow control operator while && is a Boolean operator. What is the difference?
One example of the differences, using and, you can assign values.
value = nil and value / 42
This would fail if you tried it as below
value = nil && value / 42
Original Question 1
Assuming I want to evaluate one-liners with a return statement (similar to a certain > commonly used shell/bash expression), would this be a recommended way to do it, or is there > a more recommended approach?
The way I have always seen this done in Ruby is this:
value if conditional
This will return the value if the conditional is met and nil otherwise. No need for the return statement if this is the last command in the function!
If you are using this for an early exit to a function, I prefer using an unless. For instance...
return unless arguments_are_valid
Original Question 2
foo method causes a syntax error. bar doesn't. Why?
It's a matter of operator precedence. See the example below showing how they are evaluated.
(true && return) false
(true) and (return false)
Because of the && operator precedence, the following line
true && return false
evaluates as
(true && return) false
that does not makes sense. In order to execute your code you need to use
def foo
true && (return false)
end
and doesn't suffer of the same issue because and has lower precedence than &&.
if there is need for shorten statements use
def foo
return false if true
end
def bar
return false if true
end
return is not a function :) therefore it doesn't make sense to say
when true and return is ok send a false

Using || in arguments in Ruby?

I just saw this code:
method_name(ARGV.shift || "somefile.txt")
which basically should first evalute ARGV[0] and if it doesn't exist then read from "somefile.txt".
My question was, can the && operator be also used here, and in what situations?
Also, does this concept of "passing this or this argument" to a method in Ruby have a name?
The short answer, logical operators are going to return one of its operands based on if it's truthy or falsey. In practice, nearly everything in Ruby will evaluate to true except false or nil.
Examples:
expr1 || expr2 will return (expr1 if not falsey) or (expr2)
In other words, the first truthy value or the final operand,
expr1 && expr2 will return (expr1 if falsey) or (expr2).
In other words, the first falsey value or the final operand.
As for an actual use case, a similar example would be:
Using the && operator to check for a flag in ARGV then passing the file name.
method_name(ARGV.include?('-w') && "write_file.txt")
It should be noted that this is probably not a widely accepted practice. (see comments)
However, preferring a user supplied value over a default value, by using ||, in this manner would be.
If && is used, then the argument would be nil when there is no ARGV[0] and "somefile.txt" when there is ARGV[0]. Note that elements of ARGV, if any, would be strings, so there is no possibility of ARGV[0] being nil or false when there is an element passed.
Generally, || and && are called "(short circuit) disjunction" and "(short circuit) conjunction", respectively.
A typical use case of || is to provide a default value:
foo = potentially_falesy_value || default
A typical use case of && is to provide a value that depends on the truthness of another value:
foo = hash[:bar] && hash[:bar][:baz]
|| is using for providing default values. || returns first "true" value. "True" value -- value that is interpreted as true boolean value in ruby. So first "true" value in the chain will be as the result of the expression. && returns first "false" value. Complete analogy. But it does not have such graceful application.
Apart from the obvious Boolean operator functionality, && can be used like you could in some languages such as JavaScript:
a = cond1 && cond2 && value # a is now value if cond1 and cond2,
# else nil or false (depends on cond1 and cond2)
It's not very readable (IMHO) when assigning non-Boolean variables, but it works.
first evalute ARGV[0] and if it doesn't exist then read from "somefile.txt". My ques
You are correct. The ARGV.shift || "somefile.txt" expression will evaluate to ARGV.shift if it returns some non-falsy value, and "somefile.txt" otherwise. Some other examples:
puts nil || "foo" # => "foo"
puts "foo" || "bar" # => "foo"
puts "foo" || nil # => "foo"
puts "foo" || raise # => "foo"
# and doesn't blow up, because the 'raise'
# is never evaluated
can the && operator be also used here
Sure, but is arguably of less practical value. It might be clearer to use an if in that case:
puts foo && bar
# is the same as:
if foo
puts bar
end
# or:
puts bar if foo
does this concept of "passing this or this argument to a method in Ruby" has a name?
I'm not sure if it has any 'official' name, but I commonly see this pattern being called 'default value' or 'fallback value'.

Difference between "or" and || in Ruby? [duplicate]

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 ||.

Resources