From: Marc-Andre Lafortune Date: 2011-06-23T23:43:47+09:00 Subject: [ruby-core:37323] Re: [Ruby 1.9 - Feature #4917] NilClass#to_ary Hi, On Wed, Jun 22, 2011 at 6:34 PM, Charles Nutter wrote: > > Perhaps if an optimization is needed, it could just be adding a nil check to Kernel#Array. Yes, that's a possibility I thought of. The problem lies both in the "if" (note that the included benchmark shows a ~35% performance gain) and the fact that the definition of Array() would have to change slightly. I also fail to see why Array(nil) should be optimized and not, say, Array(42) I'm feel there are many more important things to worry about. > ---------------------------------------- > Feature #4917: NilClass#to_ary > http://redmine.ruby-lang.org/issues/4917 > > Author: Jay Feldblum > Status: Rejected > Priority: Normal > Assignee: > Category: > Target version: > > > As a performance improvement in certain cases, nil should respond to to_ary. > > Kernel#Array, when passed nil, first tries to send to_ary to nil (which actually ends up calling method_missing on nil) and then tries to send to_a to nil which finally succeeds. When Kernel#Array is used often, for example in library/gem code, this can have a noticeable, if relatively small, negative impact on the overall application performance. > > � �$ irb > > � �> RUBY_VERSION > � � => "1.9.2" > > � �> require 'benchmark' > � �> def bench(times) Benchmark.bmbm{|x| x.report{times.times(&Proc.new)}} end > > � �# Let's zero the scale.... > � �> bench(10_000_000) { } > > � �# The "before" benchmark.... > � �> bench(10_000_000) { Array(nil) } > > � �# An optimization.... > � �> NilClass.class_eval { alias to_ary to_a } > > � �# The "after" benchmark.... > � �> bench(10_000_000) { Array(nil) } > � �# Much faster! > > � �# Let's see how many times method_missing actually gets called.... > � �> NilClass.class_eval { undef to_ary } > � �> class NilClass > � �> � alias method_missing_without_hit method_missing > � �> � def method_missing(name, *args, &block) > � �> � � $method_missing_hits += 1 > � �> � � method_missing_without_hit(name, *args, &block) > � �> � end > � �> end > > � �> $method_missing_hits = 0 > � �> bench(100_000) { Array(nil) } > � �# Very slow! > � �> $method_missing_hits > � � => 200005 > > � �> NilClass.class_eval { alias to_ary to_a } > � �> $method_missing_hits = 0 > � �> bench(100_000) { Array(nil) } > � �# Instantaneous! > � �> $method_missing_hits > � � => 0 > > > > -- > http://redmine.ruby-lang.org > >