1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Fix performance slowdown in Ruby 2.7+

In #34068 I introduced code that improved performance in Ruby 2.5. But recently @Jeremyevans pointed out that it made code slower in 2.7+ which Rails targets https://gist.github.com/jeremyevans/40675ac1f69b4ac405d3c6ba060cdd35. Here's the twitter thread https://twitter.com/jeremyevans0/status/1414731600693108737.

This change essentially reverts #34068

```
$ cat scratch.rb
class FooCurrent
  def try(_method_name = nil, *)
    nil
  end
end

class FooUpdated
  def try(*)
    nil
  end
end

require 'benchmark/ips'

foo_updated = FooUpdated.new
foo_current = FooCurrent.new

Benchmark.ips do |x|
  x.report("updated") { foo_updated.try(:anything) }
  x.report("current") { foo_current.try(:anything) }
  x.compare!
end

$ ruby -v
ruby 3.0.2p107 (2021-07-07 revision 0db68f0233) [x86_64-darwin19]
$ ruby scratch.rb
Warming up --------------------------------------
             updated   854.461k i/100ms
             current   687.183k i/100ms
Calculating -------------------------------------
             updated      8.418M (± 2.1%) i/s -     42.723M in   5.077403s
             current      6.619M (± 9.6%) i/s -     32.985M in   5.048477s

Comparison:
             updated:  8418315.3 i/s
             current:  6619074.1 i/s - 1.27x  (± 0.00) slower
```
This commit is contained in:
Richard Schneeman 2021-07-15 16:02:34 -05:00
parent 359efef64b
commit bb513b8541

View file

@ -4,28 +4,28 @@ require "delegate"
module ActiveSupport
module Tryable #:nodoc:
def try(method_name = nil, *args, &block)
if method_name.nil? && block_given?
def try(*args, &block)
if args.empty? && block_given?
if block.arity == 0
instance_eval(&block)
else
yield self
end
elsif respond_to?(method_name)
public_send(method_name, *args, &block)
elsif respond_to?(args.first)
public_send(*args, &block)
end
end
ruby2_keywords(:try)
def try!(method_name = nil, *args, &block)
if method_name.nil? && block_given?
def try!(*args, &block)
if args.empty? && block_given?
if block.arity == 0
instance_eval(&block)
else
yield self
end
else
public_send(method_name, *args, &block)
public_send(*args, &block)
end
end
ruby2_keywords(:try!)
@ -145,14 +145,14 @@ class NilClass
#
# With +try+
# @person.try(:children).try(:first).try(:name)
def try(_method_name = nil, *)
def try(*)
nil
end
# Calling +try!+ on +nil+ always returns +nil+.
#
# nil.try!(:name) # => nil
def try!(_method_name = nil, *)
def try!(*)
nil
end
end