Pit Capitain wrote: > Hi, > > Dan Berger's recent thread about using UnboundMethod#bind to redefine an > existing method reminded me of a problem I still have: > > What is the fastest way to redefine an existing method? > > With "fast" I don't mean the process of redefining the method, but the > time it takes to actually call the new implementation. > > 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)