Pit C. wrote:
With “redefining an existing method” I mean changing the implementation
of an existing method so that in the new implementation it is possible
to call the old one and use its return value.
I’ve seen many different techniques in the past here on ruby-talk, but I
haven’t looked at the tradeoffs. I promise to write a page on the ruby
garden wiki with the results.
Regards,
Pit
A cut is going to be just about the fastest I think since it is
essentially a subclass, although defining the “wrapping” method
requires a bit of additional overhead. Alias certainly has the least
overhead. I imagine before and after wraps as matz has suggested for
Ruby 2.0 would be faster, albiet they are more limited in capability
than cuts.
Keep in mind that every “wrap” will have a benchmark greater than the
orginal by neccessity b/c includes the originals call --so what’s
really of interest is the difference from the original. Consdiering
that it is clear what the fastest way would be. To literally extract
the source code of the oringal method and wrap it via string
manipulation and eval the result as the new method. Of course, that’s
not all that practical – for starters I think you would need something
like ParseTree to even pull it off.
Anyway here’s Ara’s benchmarks with cuts/subclass added:
Alias
class HashUsingAlias < Hash
alias :old_hset :[]=
def []=(key, value)
self.old_hset(key, value)
end
end
Bind
class HashUsingBind < Hash
hset = self.instance_method(:[]=)
define_method(:[]=) do |key, value|
hset.bind(self).call(key, value)
end
end
Override
require ‘override’
class HashUsingOverride < Hash
override(’[]=’){ def []=(k,v) super end }
end
Subclass
class HashUsingSubClass < Hash
def []=(k,v)
super
end
end
Cut (pure ruby meta-hacking version)
require ‘facets/more/cut’
class HashUsingCut < Hash; end
cut :HashUsingCutAspect < HashUsingCut do
def []=(k,v); super; end
end
require “benchmark”
def bm_report bm, title, hash_class
hash = hash_class.new
bm.report title do
100_000.times do
hash[ 1 ] = 1
end
end
end
Benchmark.bmbm do |bm|
bm_report bm, “original”, Hash
bm_report bm, “alias”, HashUsingAlias
bm_report bm, “bind”, HashUsingBind
bm_report bm, “override”, HashUsingOverride
bm_report bm, “subclass”, HashUsingSubClass
bm_report bm, “cut”, HashUsingCut
end
Rehearsal --------------------------------------------
original 0.100000 0.020000 0.120000 ( 0.125107)
alias 0.180000 0.030000 0.210000 ( 0.226911)
bind 0.460000 0.050000 0.510000 ( 0.525037)
override 0.590000 0.030000 0.620000 ( 0.630301)
subclass 0.170000 0.030000 0.200000 ( 0.210436)
cut 0.170000 0.030000 0.200000 ( 0.210003)
----------------------------------- total: 1.860000sec
user system total real
original 0.100000 0.010000 0.110000 ( 0.123498)
alias 0.170000 0.040000 0.210000 ( 0.224580)
bind 0.480000 0.030000 0.510000 ( 0.529366)
override 0.570000 0.050000 0.620000 ( 0.626580)
subclass 0.170000 0.030000 0.200000 ( 0.214458)
cut 0.170000 0.030000 0.200000 ( 0.209727)