Why is it okay to write or but not ||? - ruby

I understand there is a difference in the precedence as shown in another answer:
p foo = false || true
# => true
p foo = false or true
# => false
But it seems like there is something more that's different between or and ||.
For example:
p foo = 42 or raise "Something went wrong with foo"
# => 42
p foo = nil or raise "Something went wrong with foo"
# => Something went wrong with foo (RuntimeError)
p foo = 42 || raise "Something went wrong with foo"
# => syntax error, unexpected tOP_ASGN, expecting end-of-input
I was expecting to get:
p foo = 42 or raise "Something went wrong with foo"
# => 42
p foo = nil or raise "Something went wrong with foo"
# => Something went wrong with foo (RuntimeError)
p foo = 42 || raise "Something went wrong with foo"
# => Something went wrong with foo (RuntimeError)
But it's a syntax error. So what is happening?

Theory :
Here's a precedence table for Ruby.
It's not clear from this table but Ruby method invocation without parentheses has a lower precedence than || and =, but higher than or. See this question.
So for your code, from highest to lowest precedence :
||
=
raise "something"
or
Expression with or
foo = 42 or raise "Something went wrong with foo"
First comes = :
( foo = 42 ) or raise "Something went wrong with foo"
Then raise :
( foo = 42 ) or ( raise "Something went wrong with foo" )
Then or :
( ( foo = 42 ) or ( raise "Something went wrong with foo" ) )
Expression with ||
foo = 42 || raise "Something went wrong with foo"
First comes || :
foo = ( 42 || raise ) "Something went wrong with foo"
Here's your syntax error!
You want :
foo = 42 || (raise "Something went wrong with foo") #=> 42
or
foo = 42 || raise("Something went wrong with foo") #=> 42
or just
foo = 42 || raise
Warning!
When you have troubles with precedence, you should be careful about adding another puts or p without parentheses !
For example :
p [1,2,3].map do |i|
i*2
end
outputs :
#<Enumerator: [1, 2, 3]:map>
even though you might have expected :
[2, 4, 6]

|| and or are not the same operation.
The first is equivalent to a method call, the latter is a control flow keyword. You probably always want to use || to avoid confusion with precedence. Most style guides for Ruby have a clause that bans the use of and and or for that reason.
So then,
A or B
# can be considered equivalent to
if A then A else B end
whereas
A || B
# can be considered equivalent to
A.or { B } # given a hypothetical "logical or" method
Now let's look into your or example
p foo = false or true
is equivalent to
temp = p(foo = false) # => nil
if temp
temp
else
true
end
and thus when executed prints false and returns true
[1] pry(main)> p foo = false or true
false
=> true
[2] pry(main)> foo
=> false
whereas
p foo = false || true
is equivalent to (glossing over the difference between boolean and logical OR for now since your example is dealing with booleans anyway)
p(foo = false.|(true))
and thus when executed prints true and returns true
[1] pry(main)> p foo = false || true
true
=> true
[2] pry(main)> foo
=> true

Related

Exceptions: why does adding parenthesis change anything?

There are a few things I'd like to understand in how Ruby treats inline Error handlers
Case 1
This is a common use case
def foo
raise Error
end
bar = foo rescue 1
# => 1
bar
# => 1
It works as expected. The expression foo rescue 1 returns 1 and it is correctly assigned to bar.
Case 2
Ruby allows descructuring arrays, so this behavior seems odd.
baz = 'a'
baz, bar = foo rescue [1, 2]
# => [1, 2]
baz
# => 'a'
bar
# => nil
The expression returns the array [1, 2] but doesn't deconstruct or assign it. It completely skips the assignment altogether.
Case 3
When you wrap the the error in parenthesis, however, the deconstruction works.
baz, bar = (foo rescue [1, 2])
# => [1, 2]
baz
# => 1
bar
# => 2
Case 4
Bonus points: Raising the Error and trying to handle it inline also skips assignment
baz = raise Error rescue 1
# => 1
baz
# => nil
But adding parenthesis makes it work.
Edit:
I tested this on Ruby 1.9.3-p392 and Ruby 2.0.0
Edit 2:
I added labels to cases
Edit 3:
Apparently some folks think this isn't a question, so maybe the title wasn't obvious enough. Here's the question in full text:
Why do these inconsistencies happen, and why does adding parenthesis change anything?
Your case 2 is the same as this:
baz = 'a'
(baz, bar = foo) rescue [1, 2]
Since foo raises an error, assignment of values to baz and bar fails, so baz remains to be "a", and bar remains to be nil, a value that was assigned during the parsing stage. Then, the assignment gets rescued, and the return value would be [1, 2].
Your case 4 is the same as this:
(baz = raise Error) rescue 1
Since the righthand side of the assignment raises an error, assignment to baz fails, and baz would remain to be nil, that was assigned during the parsing stage. Then, the assignment is rescued, and the return value is 1.
Update:
Sorry, my example did not worked. I guess this is a bug in the parser as simple assignment does not suffer this issue.
bar, baz = 1,2 # bar == 1, baz == 2
bar = foo rescue [3,4] # bar == [3,4], baz == 2
bar, baz = 1,2 # bar == 1, baz == 2
bar, baz = foo rescue [3,4] # no assignment done: bar == 1, baz == 2
Even precedence of rescue can not explain why the simple assignment is done and multi- does not.

Compare the Content, Not the Results, of Procs

Using Ruby 1.9.2
Problem
Compare the content, not the results, of two procs. I understand the results can't be tested because of the halting problem but that's OK; I don't want to test the results anyway.
For instance
proc {#x == "x"} == proc {#x == "x"} => false # doh!
That returns false because the objects inside the procs are not the same.
My clunky solution
I have a work around solution that kinda sorta does what I want but it doesn't really test that the proc is "equal" to what I put in it. In my specific case the format of my procs will always be boolean tests on instance variables like this:
{#x == "x" && #y != "y" || #z == String}
I wrote a method that builds classes dynamically and creates instance variables set to specified values:
def create_proc_tester(property_value_hash)
new_class = Class.new.new
new_class.class.class_eval do
define_method(:xql?) { |&block| instance_eval &block }
end
property_value_hash.each do |key, value|
new_class.instance_variable_set("##{key}", value)
end
new_class
end
Which could be used something like this:
class Foo
attr_accessor :block
end
foo = Foo.new
foo.block = proc {#x == "x" && #y != "y" || #z == String}
tester = create_proc_tester(:x => "x", :y => "y", :z => Fixnum)
puts "Test #1: #{tester.xql? &foo.block}"
tester = create_proc_tester(:x => "x", :y => "x", :z => String)
puts "Test #2: #{tester.xql? &foo.block}"
> Test #1: false
> Test #2: true
.
.
That's all great and wonderful but I want to know if there is a better, more meta, way to do this that actually tests the contents of the proc not just a work around that solves my specific problem; something that could be used to test any proc.
I was thinking there might be a way to use the Ruby parser to get something to compare but I have no idea how. I'm researching it now but thought I'd try to see if anyone here has done this before and knows how. That might be a dead-end though because of the dynamic nature of Ruby but that's where I'm looking now.
If you're using Ruby 1.9, you may be able to use the sourcify gem.
$ irb
> require 'sourcify'
=> true
> a = proc {#x == "x"}
=> #<Proc:0x9ba4240#(irb):2>
> b = proc {#x == %{x}}
=> #<Proc:0x9ba23f0#(irb):3>
> a == b
=> false
> a.to_source == b.to_source
=> true
> RUBY_VERSION
=> "1.9.2"
We also ran into the ParseTree/Ruby 1.9 incompatibility problem at my company.
$ sudo gem install ruby2ruby ParseTree
require 'parse_tree'
require 'ruby2ruby'
require 'parse_tree_extensions'
# All of these are the same:
proc { puts 'a' }.to_ruby # => "proc { puts(\"a\") }"
lambda { puts "a" }.to_ruby # => "proc { puts(\"a\") }"
Proc.new { puts %{a} }.to_ruby # => "proc { puts(\"a\") }"
# If you need to do this with classes:
class Bar; define_method(:foo) { 'a' }; end
puts Ruby2Ruby.new.process(Unifier.new.process(ParseTree.translate(Bar)))
# will print this:
# class Bar < Object
# def foo
# "a"
# end
# end

Ruby `when' keyword does not use == in case statement. What does it use?

x == User returns true, but case x statement does not run the block associated with User. What's happening here?
u = User.new
# => #<User:0x00000100a1e948>
x = u.class
# => User
x == User
# => true
case x
when User
puts "constant"
when "User"
puts "string"
else
puts "nothing?"
end
# => nothing?
Case comparisons use === rather than ==. For many objects the behaviour of === and == is the same, see Numeric and String:
5 == 5 #=> true
5 === 5 #=> true
"hello" == "hello" #=> true
"hello" === "hello" #=> true
But for other kinds of object === can mean many things, entirely depending on the receiver.
For the case of classes, === tests whether an object is an instance of that class:
Class === Class.new #=> true.
For Range it checks whether an object falls in that range:
(5..10) === 6 #=> true
For Procs, === actually invokes that Proc:
multiple_of_10 = proc { |n| (n % 10) == 0 }
multiple_of_10 === 20 #=> true (equivalent to multiple_of_10.call(20))
For other objects, check their definition of === to uncover their behaviour. It's not always obvious, but they usually make some kind of sense..
Here is an example putting it all together:
case number
when 1
puts "One"
when 2..9
puts "Between two and nine"
when multiple_of_10
puts "A multiple of ten"
when String
puts "Not a number"
end
See this link for more info: http://www.aimred.com/news/developers/2008/08/14/unlocking_the_power_of_case_equality_proc/
In case statement , the comparison is done using === operator.
So your code is translated to following:
case x
when User === x
puts "Constant"
when "User" === x
puts "string"
else
puts "nothing"
end
Different class define === in different way:
The Class class define === so that it tests whether the righthand operand (x)is an instance of the class named by the lefthand operand (User). So , It is not surprise that User === x will be evaluated as false. Instead, User === u (u = User.new) is true.
irb(main):001:0> class User
irb(main):002:1> end
=> nil
irb(main):003:0> u = User.new
=> #<User:0xb7a90cd8>
irb(main):004:0> User === u.class
=> false
irb(main):005:0> User === u
=> true

Is this a reasonable use for &&= in Ruby?

In SO question 2068165 one answer raised the idea of using something like this:
params[:task][:completed_at] &&= Time.parse(params[:task][:completed_at])
as a DRYer way of saying
params[:task][:completed_at] = Time.parse(params[:task][:completed_at]) if params[:task][:completed_at]
where the params Hash would be coming from a (Rails/ActionView) form.
It's a kind of corollary to the well-known ||= idiom, setting the value if the LHS is not nil/false.
Is using &&= like this actually a recognised Ruby idiom that I've somehow missed or have I just forgotten a more commonly-used idiom? It is getting rather late...
It ought to be. If nothing else, params[:task] is only evaluated once when using the &&= form.
To clarify:
params[:task][:completed_at] = params[:task][:completed_at] && ...
calls [](:task) on params twice, [](:completed_at) and []=(:completed_at) once each on params[:task].
params[:task][:completed_at] &&= ...
calls [](:task) on params once, and its value is stashed away for both the [](:completed_at) and []=(:completed_at) calls.
Actual example describing what I'm trying to illustrate (based on Marc-Andre's example code; much thanks):
class X
def get
puts "get"
#hash ||= {}
end
end
irb(main):008:0> x = X.new
=> #<X:0x7f43c496b130>
irb(main):009:0> x.get
get
=> {}
irb(main):010:0> x.get[:foo] = 'foo'
get
=> "foo"
irb(main):011:0> x.get[:foo]
get
=> "foo"
irb(main):012:0> x.get[:foo] &&= 'bar'
get
=> "bar"
irb(main):013:0> x.get[:foo] = x.get[:foo] && 'bar'
get
get
=> "bar"
Note that using the "expanded" form causes "get" to be printed out twice, but using the compact form causes it to only be printed once.
Using &&=, in the case of LHS is false, it is only being read once, but not being set. This should make it clearer ...
class Test
def initialize(value)
#v = value
end
def v=(value)
puts "set"
#v = value
end
def v
puts "get=>#{#v}"
#v
end
end
t = Test.new(true)
t.v = t.v && true
puts '----'
t.v &&= true
puts '----'
t = Test.new(false) # lets make LHS false
t.v = t.v && true
puts '----'
t = Test.new(false) # lets make LHS false
t.v &&= true
The result:
get=>true
set
----
get=>true
set
----
get=>false
set
----
get=>false

Binary or "|" in ruby

Why isnt that working:
>> s = "hi"
=> "hi"
>> s == ("hi"|"ho")
NoMethodError: undefined method `|' for "hi":String
from (irb):2
>>
I don't get it.. Is there a solution for this kind of syntax? Because
s == ("hi"|"ho")
#is shorther than
s == "hi" || s == "ho"
Yes, the bitwise operator | is not defined in the String class: http://ruby-doc.org/core/classes/String.html
Consider this for expressiveness:
["hi", "ho"].include? myStr
irb(main):001:0> s = "hi"
=> "hi"
irb(main):002:0> ["hi", "ho"]
=> ["hi", "ho"]
irb(main):003:0> ["hi", "ho"].include? s
=> true
irb(main):004:0> s = "foo"
=> "foo"
irb(main):005:0> ["hi", "ho"].include? s
=> false
In most high level languages that syntax will not work, you have to stick to the longer syntax of:
s == "hi" || s == "ho"
Note that | is a bitwise or, whereas || is a regular or
You could use the include? method on array if you've got several == tests to do:
["hi", "ho"].include?(s)
Not shorter for two checks admittedly but it will be shorter for three or more.
This syntax doesn't exist in any language as far as I know.
What you are saying
s == ("hi"|"ho")
Literally translates to 'bitwise OR the strings "hi" and "ho" together and then compare them with s'. If you can't see why this is not what you are looking for, try writing down the ASCII codes for "hi" and "ho" and then bitwise ORing them together. You are going to get complete gibberish.
You could make it work that way:
irb> class Pair
def initialize(strA,strB)
#strA,#strB = strA,strB
end
def ==(string)
string == #strA || string == #strB
end
def |(other)
Pair.new(self,other)
end
end
#=> nil
irb> class String
def |(other)
Pair.new(self,other)
end
alias old_equals :==
def ==(other)
if other.kind_of? Pair
other == self
else
old_equals other
end
end
end
#=> nil
irb> ("one"|"two") == "one"
#=> true
irb> ("one"|"two") == "two"
#=> true
irb> ("one"|"two") == "three"
#=> false
irb> "one" == ("one"|"two")
#=> true
irb> "three" == ("one"|"two"|"three")
#=> true
But since this involves some monkey-patching of a fairly lowlevel class, I wouldn't advise relying on it. Other people will hate reading your code.
Ruby supports binary 'or' and other binary operations on values of type Fixnum and Bignum, meaning any integer. Bitwise operations aren't supported on strings or any other type, as far as I know.
As other people have mentioned, you probably want something other than binary operations altogether. However, you can easily get integer representations of characters, so you can compare characters like so:
a = "Cake"
b = "Pie"
puts a[0] | b[0] # Prints "83" - C is 67 and P is 80.
You can get an array of the comparisons easily with some conversions.
a = "Cake"
b = "Pie " # Strings of uneven length is trivial but more cluttered.
a_arr = a.split(//)
b_arr = b.split(//)
c_arr = []
a.each_with_index { |char, i| c.push(a[i].to_i | b[i].to_i) }
# If you *really* want an ASCII string back...
c = c_arr.collect(&:chr).join
You could use a regex:
Like so:
regex = /hi|ho/
s = "hi"
t = "foo"
s =~ regex
#=> 0
t =~ regex
#=> nil

Resources