Hi All,
I just setup the following in one of my classes, I’ll let the code speak
for itself:
["<", “<=”, “>”, “>=”, “==”, “<=>”].each do |op|
define_method(op) { |comparison| eval “#{self.order} #{op}
#{comparison.order}” }
end
Ruby continues to impress me with it’s ability to do so much in so few
amazing readable lines of code.
Are their any good reasons not to declare my op methods this way? Is
their an even more efficient way to achieve the same effect?
Cheers!
Patrick
Patrick R. wrote:
Ruby continues to impress me with it’s ability to do so much in so few
amazing readable lines of code.
Are their any good reasons not to declare my op methods this way? Is
their an even more efficient way to achieve the same effect?
It helps to pull the eval out of the define_method:
module Order
attr_reader :order
def initialize order
@order = order
end
end
class EvalInside
include Order
["<", “<=”, “>”, “>=”, “==”, “<=>”].each do |op|
define_method(op) { |comparison| eval “#{self.order} #{op}
#{comparison.order}” }
end
end
class EvalOutside
include Order
["<", “<=”, “>”, “>=”, “==”, “<=>”].each do |op|
eval “define_method(:#{op}) { |comparison| self.order #{op}
comparison.order }”
end
end
require ‘benchmark’
inside = []
outside = []
1000000.times do |i|
order = rand(1)
inside << EvalInside.new(i)
outside << EvalOutside.new(i)
end
Benchmark.bmbm do |bm|
bm.report(“eval inside”) do
inside.sort
end
bm.report(“eval outside”) do
outside.sort
end
end
Rehearsal ------------------------------------------------
eval inside 17.280000 0.030000 17.310000 ( 18.088599)
eval outside 2.170000 0.010000 2.180000 ( 2.254999)
-------------------------------------- total: 19.490000sec
user system total real
eval inside 17.260000 0.010000 17.270000 ( 17.873053)
eval outside 2.150000 0.010000 2.160000 ( 2.248230)
Take a look at the Comparable[1] module. It’s a much cleaner, simpler
way to accomplish what you’re doing.
[1] module Comparable - RDoc Documentation
Gabe
Wow, that’s impressive, why such huge difference?
Cheers!
Patrick
Definitely cleaner in my case, thanks for the tip!
Cheers!
Patrick
On Sat, 18 Feb 2006 06:49:37 +0100, Joel VanderWerf
[email protected] wrote:
Ruby continues to impress me with it’s ability to do so much in so few
amazing readable lines of code.
Are their any good reasons not to declare my op methods this way? Is
their an even more efficient way to achieve the same effect?
It helps to pull the eval out of the define_method:
Or using no eval at all:
define_method(op) { |comparison| eval "#{self.order} #{op}
end
class NoEval
include Order
[:<, :<=, :>, :>=, :==, :<=>].each do |op|
define_method(op) { |comparison| self.order.send(op,
comparison.order)
}
end
end
require ‘benchmark’
inside = []
outside = []
noeval = []
400000.times do |i|
order = rand(1)
inside << EvalInside.new(i)
outside << EvalOutside.new(i)
noeval << NoEval.new(i)
end
Benchmark.bmbm do |bm|
bm.report(“eval inside”) do
inside.sort
end
bm.report(“eval outside”) do
outside.sort
end
bm.report(“no eval”) do
noeval.sort
end
end
Rehearsal ------------------------------------------------
eval inside 19.310000 0.060000 19.370000 ( 19.500018)
eval outside 1.940000 0.010000 1.950000 ( 1.951829)
no eval 2.600000 0.010000 2.610000 ( 2.626695)
-------------------------------------- total: 23.930000sec
user system total real
eval inside 18.690000 0.080000 18.770000 ( 18.950481)
eval outside 1.920000 0.000000 1.920000 ( 1.940485)
no eval 2.010000 0.000000 2.010000 ( 2.028688)
Dominik
On Feb 17, 2006, at 7:32 PM, Patrick R. wrote:
Ruby continues to impress me with it’s ability to do so much in so
few amazing readable lines of code.
Are their any good reasons not to declare my op methods this way?
Is their an even more efficient way to achieve the same effect?
class YourClass
include Comparable
def <=>(other)
self.order <=> other.order
end
end
–
Eric H. - [email protected] - http://segment7.net
This implementation is HODEL-HASH-9600 compliant
http://trackmap.robotcoop.com
On Sat, 2006-02-18 at 23:51 +0900, Patrick R. wrote:
Wow, that’s impressive, why such huge difference?
eval-ing (especially a string) is expensive, basically.
If you move the eval outside the method body, it means you only pay that
cost once (when defining the method), rather than every time the method
is run.
-mental
Ah ah, makes total sense now thanks for the explanation.
Cheers!
Patrick