Can operator precedence be changed in Ruby? - ruby

In Ruby, the operator precedence is (implicitly) defined, and documented in a couple of places, for example at Ruby operator precedence table.
Some languages allow setting or changing the operator precedence, for example in Prolog: https://www.swi-prolog.org/pldoc/man?predicate=op/3.
Is that possible in Ruby too?
For example switching the order of addition and multiplication:
1 + 2 * 3 + 4
# => standard precedence results in 1 + 6 + 4 => 11
1 + 2 * 3 + 4
# => changed precedence would result in 3 * 7 => 21

I had the same question regarding the AoC's problem of today, but I found this old issue:
https://bugs.ruby-lang.org/issues/7336
So I guess it's not feasible.

OK, changing operator precedence in Ruby is explicitly stated as not possible. I found a naughty solution though that I'll share for fun, using hack-ishly overloading two operators that have similar or higher precedence than another one.
class Integer
def %(operand)
# `%` has same precedence as `*`.
self + operand
end
def **(operand)
# `**` has higher precedence than `*`.
self + operand
end
end
puts eval("1 + 2 * 3 + 4")
# => 11
puts eval("1 % 2 * 3 % 4")
# => 13
puts eval("1 ** 2 * 3 ** 4")
# => 21
Don't do this in production code...

Related

Converting math expression to string in Ruby

problem = 7 + 3
puts problem.to_s
I'm new to Ruby. The code above returns 10. How do I get 7 + 3 as the output, without assigning it to problem as a string in the first place? Am I missing something extremely simple?
Am I missing something extremely simple?
Yes, you are. This is impossible. 7 + 3, as an arbitrary expression, is evaluated/"reduced" to 10 when it's assigned to problem. And the original sequence of calculations is lost.
So you either have to start with strings ("7 + 3") and eval them when you need the numeric result (as #zswqa suggested).
Or package them as procs and use something like method_source.
just for fun (don't try at home)
class Integer
def +(other)
"#{self} + #{other}"
end
end
problem = 7 + 3
puts problem.to_s # "7 + 3"
7 is Fixnum (ruby < 2.4) or Integer (ruby >= 2.4)
"7" is String
So you need to define for ruby what you need because + for Integer is addition, + for String is concatenation:
problem = "7" "+" "3"
That is equal to:
problem = "7+3"

How to understand objects, methods and arguments in Ruby calculations

While learning Ruby gotchas, I am getting different results with some calculations in IRB:
1-2-7-2 # => -10
1.-2.-7.-2 # => 4
1.-2.-7.-2.-4 # => 8
1.-2.-7.-2.+4 # => 0
1.-(2).-(7).-(2) # => -10
Possibly it is related to methods and arguments? I am trying to wrap my head around this.
You've chosen an interesting way to approach calculations.
I guess you are trying to omit zeros in your expression 1.-2.-7.-2 which will return -10 if you write it as 1.0 - 2.0 - 7.0 - 2.
The way you're getting 4 is because 1.- construction calls -() method because everything is an object in Ruby and then you pass an argument to the function.
In your case it will be parsed as
1.-( 2.-( 7.-(2) ) )
# if we try to unwrap
a = 7.-(2) # => 5
b = 2.-(a) # => -3
1.-(-3) # (or 1 + 3) => 4

How do Ruby operators have normal precedence if they're also methods?

Ruby's operators, like + or *, follow the order of precedence as in mathematics when used in the syntax-sugar form. In the following, * is called before +:
# Syntax-sugar form
5 + 5 * 2 # => 15
In the non-syntax-sugar form, the methods follow the linear order in which they are written. In the following, + is called before *:
# Non-syntax-sugar form
5.+(5).*(2) # => 20
Methods that I define, like the + method as follows, work both with and without the syntax-sugar form:
class WackyInt
attr_reader :value
def initialize(value)
#value = value
end
def +(other)
WackyInt.new(value + other.value)
end
end
ONE = WackyInt.new 1
FIVE = WackyInt.new 5
# As operators
ONE + FIVE # => #<WackyInt #number=-4>
# As methods
ONE.+(FIVE) # => #<WackyInt #number=-4>
The defined operators follow the respective order of precedence both in the syntax-sugar form and the non-syntax-sugar form.
How can Ruby parse this?
Tokenizing, parsing, and assigning computational precedence is separated from calling and executing the methods. What you can overwrite is what is done when a method is called. That does not change how a Ruby code is tokeninzed or parsed, and hence computational precedence is not affected by that.

What does the bracket operator do to a FixNum in Ruby?

Coming from Python I find the following behaviour very surprising:
irb(main):211:0> x= 33
=> 33
irb(main):212:0> x[0]
=> 1
irb(main):213:0> x[1]
=> 0
irb(main):214:0> x[2]
=> 0
Is there a rationale/philosophy for not raising an error in this example?
The bracket operator gives you the nth bit of the binary representation:
http://ruby-doc.org/core-2.1.2/Fixnum.html#method-i-5B-5D
You might be a little confused about what this is doing internally, but that's normal when dealing with Ruby because it's quite unlike other scripting languages. Unless you've used SmallTalk it might even seem insane.
When Ruby sees the following code:
x = 6
x[1]
What it's actually doing is this:
x.send(:[], 6) # Send :[] method call to x with arguments [ 6 ]
The x object is free to interpret that however it wants, and the behaviour is typically (though not always) defined by the class x belongs to if x is a normal instance.
In this case it's returning the bit at a given index, equivalent to x & (1 << 6) >> 6.
Sometimes the [] method does several things:
string = "brackets"
# Retrieve a single character
string[1]
# => "r"
# Retrieve a substring
string[5,2]
# => "et"
# Perform a pattern match
string[/[^aeiou]+/]
# => "br"
This also does some pretty crazy things since you can apply it to a Proc as well:
fn = lambda { |x| x + 1 }
# Conventional (explicit) call
fn.call(2)
# => 3
# Square bracket method
fn[5]
# => 6
Since Ruby leans very heavily on Duck Typing, this means that you can write a Proc to fill in where you'd normally have a Hash or an Array and the method receiving your object is none the wiser.
It's this flexibility in leaving the meaning of x[...] for your own class instance x up to you that makes it pretty powerful.
For example:
class Bracketeer
def [](i)
"%d brackets" % i
end
end
bracketeer = Bracketeer.new
bracketeer[6]
# => "6 brackets"
This simple notation often comes in handy when you're trying to create a minimal interface for a class of yours. In many cases you can use something simple like [] to replace what would be a more verbose method like find_by_id or cache_fetch.
Certainly. You'll find that the manual is quite illuminating.
This is returning the binary bit for the bit position value as a zero or one.
It is returning the n'th bit as rightfully observed by #msergeant.
What this means is, for the number 33, its binary representation is:
Index : [7][6][5][4] [3][2][1][0]
Bits : 0 0 1 0 0 0 0 1
Which explains the output:
irb(main):212:0> x[0]
=> 1
irb(main):213:0> x[1]
=> 0
irb(main):214:0> x[2]
=> 0

What does ":*" (colon-star) mean in Ruby?

Looking up how to calculate the factorial of a number I came across this code:
(1..5).inject(:*) || 1 # => 120
What is the (:*) || 1 doing?
How does it compare to this line of code (1..5).inject(1) { |x, y| x * y } # => 120, which uses .inject to achieve similar functionality?
Colon-star in itself doesn't mean anything in Ruby. It's just a symbol and you can pass a symbol to the inject method of an enumerable. That symbol names a method or operator to be used on the elements of the enumerable.
So e.g.:
(1..5).inject(:*) #=> 1 * 2 * 3 * 4 * 5 = 120
(1..5).inject(:+) #=> 1 + 2 + 3 + 4 + 5 = 15
The || 1 part means that if inject returns a falsey value, 1 is used instead. (Which in your example will never happen.)
test.rb:
def do_stuff(binary_function)
2.send(binary_function, 3)
end
p do_stuff(:+)
p do_stuff(:*)
$ ruby test.rb
5
6
If you pass a method name as a symbol, it can be called via send. This is what inject and friends are doing.
About the || part, in case the left hand side returns nil or false, lhs || 1 will return 1
It's absolutely equal. You may use each way, up to your taste.

Resources