From: danzoid61@... Date: 2020-09-23T00:43:13+00:00 Subject: [ruby-core:100079] [Ruby master Feature#4917] NilClass#to_ary Issue #4917 has been updated by DanRathbun (Dan Rathbun). y_feldblum (Jay Feldblum) wrote in #note-6: > This minor performance issue becomes a huge problem when NilClass#method_missing is defined, such as in ActiveSupport (https://github.com/rails/rails/blob/master/activesupport/lib/active_support/whiny_nil.rb), which is a popular choice when developing a Rails application. > I'm curious, now that Ruby 2.x has refinements (and we're near 10 years on,) would there be acceptable speed improvements using refinements rather than direct-patching (ie, hacks) ? ---------------------------------------- Feature #4917: NilClass#to_ary https://bugs.ruby-lang.org/issues/4917#change-87636 * Author: y_feldblum (Jay Feldblum) * Status: Rejected * Priority: Normal ---------------------------------------- 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 -- https://bugs.ruby-lang.org/ Unsubscribe: