Ruby interpreter optimization - ruby

I was looking for information on Ruby's interpreter. I know it's an interpreted language and I wanted information as to whether optimization was done on the fly. A simple example would be the fiz-buzz problem. Does the interpreter convert trying to solve x%3 == 0 && x%5 == 0 to x%15 == 0 ?
It is easy to see gcc flags and what they do. Is there somewhere I can see the same for ruby?
What does the interpreter do exactly?

Since it is an interpreted language, it will run through the code one line at a time, until the first error. There are some optimizations as to how each line is evaluated, but these should also appear in other languages. e.g. lazy evaluation:
false && x>4 && x!=0
after the false followed by logical 'and', it just ignores the rest. You can have the interpreter load certain things on startup in your ~/.irbrc , if you wish.

Not really an answer, but a counter-example:
class Fixnum
def %(obj)
obj < 10 ? 0 : 1
end
end
x = 15
x % 3 == 0 && x % 5 == 0
# => true
x % 15 == 0
# => false
It's hard to optimize this expression without knowing what x is or how x#% is implemented.

Related

if statement after variable assignment - how common?

I was recently discussing the following Ruby syntax with a colleague:
value = if a == 0
"foo"
elsif a > 42
"bar"
else
"fizz"
end
I haven't seen this sort of logic much personally, but my colleague notes that it's actually a fairly common Rubyism. I tried googling the topic and found no articles, pages, or SO questions discussing it, making me believe it might be a very matter-of-fact technique. Another colleague, however, finds the syntax confusing and would instead write the above logic like this:
if a == 0
value = "foo"
elsif a > 42
value = "bar"
else
value = "fizz"
end
The disadvantage there being the repeated declarations of value = and the loss of an implicit else nil, if we wanted to use it. This also feels like it lines up with a lot of other syntactical sugar features found in Ruby.
My question is, how common is this technique in Ruby? Is there some sort of consensus on whether the community feels like this should be used or avoided?
value = if condition
x
else
y
end
is common. It lends itself to cleaning up this situation:
if condition
value = x
else
value = y
end
Have a look at this Ruby style guide. It's a popular guide in how Ruby code should be written.
https://github.com/bbatsov/ruby-style-guide#use-if-case-returns
The fact that if and case return values makes for some very tight, tidy, and yet still understandable code. It's a common pattern in Ruby when you're dealing with assignment through branching.
The way I tend to approach formatting these is to apply a level of indentation to make the assignment clear, but not overly "push" the code in too far:
value =
if a == 0
"foo"
elsif a > 42
"bar"
else
"fizz"
end
Or if you want a case:
value =
case
when a == 0
"foo"
when a > 42
"bar"
else
"fizz"
end
In many cases you'll see a method that has an if as the body to determine the result:
def value(a)
if a == 0
"foo"
elsif a > 42
"bar"
else
"fizz"
end
end
Then there's no quirky indentation necessary.

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

Ruby Multiple AND Evaluations For Integer Value

I have, on a few occasions, found myself needing to write a rather verbose if statement in some ruby scripts.
The statement would look something like this:
if long_var_name == 0 && very_different_name == 0 && other_third_var == 0 && additional_variable == 0 && name_five == 0 && longest_variable_name_six == 0
# (possibly even more conditions)
# do stuff here...
end
It seems like there has to be a more elegant way to do this.
The problem is, if and and aren't exactly easy to research with google, as basic english words. So I've come up empty-handed.
Does anyone know a way to shorten this kind of situation?
It can become a nightmare to read when you have even more of them.
Sometimes variable renaming isn't an option.
The names are sometimes vastly different.
Note: I found a clever solution for similar situations with OR:
Ruby Multiple OR Evaluations For String Value
If you have an array and are specifically testing for zero, you can do:
vars1 = [0,0,3,0,0]
vars2 = [0,0,0,0,0]
vars1.all?(&:zero?) # false
vars2.all?(&:zero?) # true
EDIT: Based on OP's added conditions of having different names for the values:
if [long_var_name_1,long_var_name_2,long_var_name_3].all?(&:zero?)
# do stuff here...
end
In your specific case, I would write
if [a, b, c, d, e, f].all? { |var| var == 0 }
There's noting wrong about chaining and conditions IMHO.
Have you thought of breaking it up into logic expressions? Basically break it up into smaller bits of logical groupings and its easier to read e.g.
grp_1_zero = var_1 == 0 && var_2 == 0 && var_3 == 0
grp_2_zero = var_a == 0 && var_b == 0 && var_c == 0
grp_3_zero = var_z == 0 && var_x == 0 && var_y == 0
if grp_1_zero && grp_2_zero && grp_3_zero
#code here
end
Another, for array a:
a == Array.new(a.size,0)
You can use Enumerable#all? and the Symbol#to_proc utilisation of the Fixnum#zero? method.
foo = 0
bar = 0
baz = 0
[foo, bar, baz].all? &:zero?
# => true
one = 1
two = 2
[foo, one, two].any? &:zero?
#=> true
Note that you can also provide any anonymous function for the test.
owns_peanuts = ->(person){ person.inventory.contains :peanuts }
[bill, david, mike].any? &owns_peanuts

Ruby: enumerator can't be coerced to Fixnum; struggling with Project Euler #5

The challenge is to find the smallest integer foo for which:
foo % 1..20 == 0
My current attempt is brute force
until foo % 1.upto(20) == 0 do
foo++
end
This outputs the error unexpected keyword end. But if I don't put the end keyword into irb the code never runs, because the block isn't closed.
I made an empty test case to see where my error lays
until foo % 1.upto(20) == 0 do
end
This throws a new error: enumerator can't be coerced to a fixnum. I imagine this means you can't directly perform modulus upon a range and expect a neat boolean result for the whole range. But I don't know where to go from here.
My first attempts forewent brute force in favor of an attempt at something more efficient/elegant/to-the-point and were as follows:
foo = 1
1.upto(20) {|bar| foo *= bar unless foo % i == 0}
gave the wrong answer. I don't understand why, but I'm also interested in why
foo = 1
20.downto(1) {|bar| foo *= bar unless foo % i == 0}
outputs a different answer.
EDIT: I would have used for loops (I got my feet wet with programming in ActionScript) but they do not work how I expect in ruby.
Your first solution is wrong because 1.upto(20) is an enumerator, that is, essentially an iterator over the values 1 to 20, and it cannot be used as a number for modulo or comparison to another number, since it itself isn't a number.
You really need two "loops" here:
foo = 1
foo += 1 until (1..20).all? { |i| foo % i == 0 }
the first loop is the until, and then the all? is another loop of sorts, in that it ensures that the block ({ |i| foo % i == 0 }) is true for each element in the range it is called on ((1..20)). Note that I'm using the one-line "backwards" syntax (which also works for if, unless, while, …)—the above is equivalent to:
foo = 1
until (1..20).all? { |i| foo % i == 0 } do
foo += 1
end
# foo => 232792560
Also, this is incredibly inefficient, Project Euler often involves a bit more math than programming, and a non-brute-force solution will likely involve more math but be far faster.
Try this:
until 1.upto(20).reject{|i| foo % i == 0 }.empty? do
foo += 1
end
I know it's not directly the OP question, but this is way easier to achieve with just:
puts (1..20).reduce(:lcm)
It's so simple that it seems like isn't fair to solve it this way, but that's precisely why Ruby is my language of choice for Project Euler.
See also this question
If this were me, I'd define a function to test the condition:
def mod_test(num)
test = (1..20).map {|i| num % i == 0}
test.all? # all are true
end
and then a loop to try different values:
foo = 20
until mod_test(foo) do
foo += 20
end
(Thanks to Dylan for the += 20 speedup.)
I'm sure that there's a clever way to use the knowledge of foo % 10 == 0 to also imply that foo % 5 == 0 and foo % 2 == 0, and perform only tests on prime numbers between 1 and 20, and probably even use that information to construct the number directly -- but my code ran quickly enough.

Why is assignment treated differently in this single line conditional?

I've read a few things, including this and this, but I think the below example is different than what they're talking about. One person actually raises a similar example in the discussion but it's ignored.
So, run in irb (ignore the warnings about assignment in the conditional):
(puts x) if (x = 0) # NameError: undefined local variable or method `x'...
x # => 0
(puts x) if (x = 0) # "0", => nil
but the second time there's no error.
Does this make any sense, even in a "once you understand what the parser is really doing and that this just some optimization it all becomes clear" kind of way? Because to me, it seems pretty undesirable.
To be clear, the above conditional should be equivalent (right?) to
if newvar=0
puts newvar
end
which does not raise an error.
Update: There have been even more posts on this topic since this question was asked. For example,
http://seejohncode.com/2012/07/31/ruby-gotcha-single-line-conditionals/.
Oddly enough, this works fine in Rubinius:
Welcome to IRB. You are using rubinius 1.2.4dev (1.8.7 7ae451a1 yyyy-mm-dd JI)
>> (puts x) if (x = 0) #=> nil
0
I'm inclined to say it's a weird parsing bug in MRI.
I think the difference in this case is whether the variable exists when it parses the line. In the case of:
if x=0
puts x
end
the variable x is defined before it parses the line that uses x.
In other words, the error message is a parse time error, not a runtime error.
I think in this you are assigning 0 to x.
(puts x) if (x = 0)
i think it should be
(puts x) if (x == 0)
First, check that you mean x=0 in the conditional clause.
Second, puts x if x = 0 is not equivalent to:
if x = 0
puts x
end
In your case, x is not declared yet for puts x so it cannot see it.

Resources