Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby lacks constant expressions optimization?

I'd expect Ruby's parser would make this trivial optimization, however is seems it does not (speaking about YARV implementations, Ruby 1.9.x, 2.0.0):

require 'benchmark'

def fib1
    a, b = 0, 1
    while b < 9999**4000
        a, b = b, a+b
    end
    puts "\tdone !"
end

MAX_FIB = 9999**4000
def fib2
    a, b = 0, 1
    while b < MAX_FIB
        a, b = b, a+b
    end
    puts "\tdone !"
end

if __FILE__ == $0
    Benchmark.bm do |r|
        r.report('plain') { fib1 }
        r.report('predefined constant') { fib2 }
    end
end

plain    done !
 32.810000   0.220000  33.030000 ( 33.069854)
predefined constant    done !
  0.120000   0.000000   0.120000 (  0.119303)

As both methods are identical except use of predefined constant instead of an constant expression in the second, it seems Ruby interpreter calculates power constant each loop again and again.

Is there some material why Ruby does not do this basic optimization at all or just in some specific cases ?

like image 899
David Unric Avatar asked Jan 16 '14 14:01

David Unric


1 Answers

I am sorry for giving another answer, but I don't want to remove or edit my previous one because of the interesting discussion under it.

As Jörg W Mittag said, ruby has to calculate expression given to while each time because it is simply impossible to say it is constant. For an extreme example, I come up with following code:

class Fixnum
  alias :original_plus :+

  @@increment = 0
  def self.increase!
    @@increment = @@increment.original_plus 1
  end

  def +(other)
    (original_plus(other)).original_plus(@@increment)
  end 
end

while 1+1 < 5
  puts Fixnum.increase!
end
puts 'done' 

# 1 
# 2
# 3
# done
like image 79
BroiSatse Avatar answered Oct 06 '22 14:10

BroiSatse