Why does expression (true == true == true) produce a syntax error? - ruby

Ruby:
true == true == true
syntax error, unexpected tEQ
vs. JavaScript:
true == true == true
// => true
vs. C:
1 == 1 == 1
// => 1

Association direction, which controls the order of operators having their arguments evaluated, is not defined for the == method, same as for ===, !=, =~ and <=> methods as well (all of which have the same precedence and form a separate precedence group exclusively).
Documentation
Thus evaluation order in case of multiple operators from the list mentioned above being chained in a row should be set explicitly via either
parenthesis ():
(true == true) == true # => true
true == (true == true) # => true
or dot operator . (can be omitted for the last equality check in a row):
true .== true == true # => true

TL;DR The syntax implies that all 3 values are equal this is not what it does in javascript or C, so by ruby giving a syntax error the door is open for this to be implemented in the future.
If I understand the question correctly value_a == value_b == value_c should only return true if they are all equal using == as the comparison operater as shown in this method
# version 1
def compare_3_values(a, b, c)
a == b && a == c && b == c
end
there is another possible expected outcome though. to implement this as shown in the previous answer:
#version 2
def compare_3_values(a, b, c)
(a == b) == c
end
The results are worlds apart.
JavaScript always uses version 2 which is pretty useless as the 3rd item is always being compared against true or false (0 or 1 if the 3rd item is an integer) that's why false == false == true returns true.
The good news is that because ruby gives a syntax error it's the only language that can implement this without breaking everyone's code.
for any other language it would break so much code that even if it were implemented in a later major version there would need to be a flag/setting to turn this on or off for years to come, hence it will never be worthwhile.
Some interesting results in Ruby
false .== false == true
=> true
false .== true == false
=> true
true .== false == false
=> true
false .== false == false
=> false
true .== true == false
false
And in javascript
false == false == true
=> true
false == true == false
=> true
true == false == false
=> true
false == false == false
=> false
true == true == false
=> false
Edit tested in C as well, acts similar to JavaScript in that it compares the result of the first two values against the third value

The first answer is excellent, but just in case it's not completely clear (and people asking why), here are few more examples.
In C, the == operator is left-to-right associative and boolean is represented as 1 (true) and 0 (false), so the first 1 == 1 evaluates to 1 (true) and then you are evaluating the result of first expression with the second. You can try:
2 == 2 == 2 // => 0
Which in C, is evaluated as:
(2 == 2) == 2
1 == 2 // => 0
In Javascript, similarly to C, == is left to right associative. Let's try with 0 this time (although the same example from C would work as well):
0 == 0 == 0
false
Again:
0 == 0 == 0
true == 0 // => false
In Ruby == does not have associative properties, ie. it can't be used multiple times in single expression, so that expression can't be evaluated. Why that decision was made is a question for the author of the language. Further, Ruby doesn't define numeric 1 as a boolean, so 1 == true evaluates to false.
The second answer states there are some "weird" cases in Ruby, but they all evaluate as expected:
(1 == 1) == 1
true == 1 # => false
1 == (1 == 1)
1 == true # => false
1 .== 1 == 1
(1 == 1) == 1
true == 1 # => false
false .== false == true
(false == false) == true
true == true # => true
false .== true == false
(false == true) == false
false == false # => true
true .== false == false
(true == false) == false
false == false # => true
false .== false == false
(false == false) == false
true == false # => false
true .== true == false
(true == true) == false
true == false # => false

Related

Why am I getting a Type Error: Range can't be coerced into Integer for line 11, if max == ele % 0?

The following returns a Type Error in my conditional within the do block
Range can't be coerced into Integer
def coprime?(num_1, num_2)
min = [num_1, num_2].min
max = [num_1, num_2].max
[2..min].each do |ele|
if max % ele == 0
return true
end
end
return false
end
p coprime?(25, 12) # => true
p coprime?(7, 11) # => true
p coprime?(30, 9) # => false
p coprime?(6, 24) # => false
Because ranges in Ruby should have the form (start..end). In your case [2..min] is an array with only one element, where that element is a range.
You can replace the [] with () to create a range from 2 to min:
(2..min).each do |ele|
if max % ele == 0
return true
end
end
2..min is a range, therefore [2..min] is actually an array with 1 element and the ele will be 2..min
It should be (2..min).each do |ele| instead of [2..min].each do |ele|
Also you don't need to return false at the end just false is enough.

Is there a better way to compare strings in a reasonable amount of time?

I have this Ruby function that tells me if two strings are "almost" equal, that is, if all characters in the string are identical and ordered in the same way except for one. So for instance, these are equal
equal
eual
but these are not
eal
equal
(two characters are missing in the above). So with help, I have come up with this
(lcs(a,b) == shortest && longest.length - shortest.length == 1)
in which las is defined by
def lcs(xstr, ystr)
return "" if xstr.empty? || ystr.empty?
x, xs, y, ys = xstr[0..0], xstr[1..-1], ystr[0..0], ystr[1..-1]
if x == y
x + lcs(xs, ys)
else
[lcs(xstr, ys), lcs(xs, ystr)].max_by {|x| x.size}
end
end
but my function is taking an extraordinarily long time. Note my benchmark below
2.4.0 :011 > timing = Benchmark.measure { StringHelper.lcs("navesxkolsky|1227000", "navsxkolsky|1227000") }
=> #<Benchmark::Tms:0x007fa1753830d8 #label="", #real=21.341279999993276, #cstime=0.0, #cutime=0.0, #stime=0.030000000000000027, #utime=21.28, #total=21.310000000000002>
Is there something I'm missing here that can get my comparison time down to like one second instead of 21?
Try this. The main idea is that if the method is to return false, it will do so as soon as that is known, even if rudundant code is required. (The method below still works if the line return false if (sz1-sz2).abs > 1 is removed.)
def equal_but_one?(str1, str2)
sz1 = str1.size
sz2 = str2.size
return false if (sz1-sz2).abs > 1
i = [sz1, sz2].max.times.find { |i| str1[i] != str2[i] }
return false if i.nil?
case sz1 <=> sz2
when 0
str1[i+1..-1] == str2[i+1..-1]
when -1
str2[i+1..-1] == str1[i..-1]
when 1
str1[i+1..-1] == str2[i..-1]
end
end
equal_but_one?('cat', 'cut') #=> true
equal_but_one?('bates', 'bats') #=> true
equal_but_one?('buss', 'bus') #=> true
equal_but_one?('cat', 'cat') #=> false
equal_but_one?('pig', 'pigs') #=> true
equal_but_one?('pig', 'pegs') #=> false
equal_but_one?('', '') #=> false
equal_but_one?('', 'a') #=> true
require 'benchmark'
Benchmark.measure { equal_but_one?("navesxkolsky|1227000", "navsxkolsky|1227000") }.real
#=> 1.6000005416572094e-05

ruby function returns different boolean value in irb vs repl.it

I have written the following function to check if a number is prime:
def is_prime?(number)
arr = (2..number).to_a.select {|m| number % m == 0}
arr.length == 1 ? true : false
end
When passing 4 or 9 as the number in irb, it correctly returns false. However, in repl.it these evaluate to true.
Here is the test code I am running on repl.it:
puts("\nTests for #is_prime?")
puts("===============================================")
puts('is_prime?(2) == true: ' + (is_prime?(2) == true).to_s)
puts('is_prime?(3) == true: ' + (is_prime?(3) == true).to_s)
puts('is_prime?(4) == false: ' + (is_prime?(4) == false).to_s)
puts('is_prime?(9) == false: ' + (is_prime?(9) == false).to_s)
puts("===============================================")
And its output:
Tests for #is_prime?
===============================================
is_prime?(2) == true: true
is_prime?(3) == true: true
is_prime?(4) == false: true
is_prime?(9) == false: true
===============================================
What could be causing this variation?
I tried on repl.it and I get false for both 4 and 9.
Anyway, two small improvements to your code: - you can call select directly on the range, without turn it in an array
- you can return the value of expression itself, without specify true and false
def is_prime?(number)
arr = (2..number).select {|m| number % m == 0}
arr.length == 1
end
You have been confused by the output of your test, which is reporting both the expected result of the function, and the alctual result of the function was correct (that is, was what the test expected):
is_prime?(2) == true: true
is_prime?(3) == true: true
is_prime?(4) == false: true
is_prime?(9) == false: true
^ ^
| |
| true if the test passed; false if failed
|
What the function should have returned
If the rightmost column contains all "true" values, then the function has passed all of its tests.

Why `z || y == 0` does not return what I expect?

So I am taking the Ruby course in Codecademy and I write this code
z = 39
y = 39
if z && y != 39
print "God if it prints this, this code will be a failure!"
elsif z || y == 0
print "dont print this code"
else
print "Success!"
end
And for some reason it runs the elsif and says "dont print this code" can someone explain that to me?
You have two things to understand here: how && works and how Ruby convert object to true/false.
How && works:
You write:
if z && y != 39
You expect Ruby to interpret like this:
if (z != 39) && (y != 39)
But actually Ruby interpret it like this:
if (z) && (y != 39)
Convert object to true / false
Any Ruby object that is not nil or false will evaluate to true. So in your case, we have:
if z && y != 39
Which is:
if true && false # z is not nil, so true, and y == 39 so the second part is false
which of course evaluate to false.
Then
if z || y == 0
Which is:
if true || false # z is still not nil, y != 0 so the second part is false
true || false evaluate to true, so the "dont print this code" is outputted.
Because z being the object is not taken as false as you have z=39, not set to boolean literal value false or nil
For Ruby any non nil or any object set to boolean literal value false would return true in an expression returning boolean type value.

Is true && true == false?

Am I missing something or is this a bug in ruby?
a = %w(foo bar baz)
a.include? "foo" # => true
a.size == 3 # => true
a.include? "foo" && a.size == 3 # => false
a.include? "foo" && a.size == 3
is evaluated as
a.include? ("foo" && a.size == 3)
and because
"foo" && a.size == 3 #=> true
this is equivalent to
a.include? true
which is false
Is true && true == false?
No.
irb(main):003:0> true && true == false
=> false
What you meant to check is
a.include?("foo") && a.size == 3
Your condition is checking if "foo" && a.size == 3 (which is true because "foo" is neither nil nor false) is included in the array.
The solution of Zack's comment is correct too, but looking a bit unusual:
(a.include? "foo") && a.size == 3
One reason why the whole expression is considered the method's argument in case of missing parentheses is you can do:
puts 3 + 4 * 5 - 6

Resources