Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.Try vs && performance

Suppose I have an incoming value from a SQL query, like so:

grok = Foo.select(:foo_attr1, :foo_attr2).first

foo_attr2 is a nullable field. Now suppose I need to do stuff to the output if it exists.

krug = grok.foo_attr2.try(:bar).try(:baz)
gnar = grok.foo_attr2 && grok.foo_attr2.bar.baz # Assumes bar will always return output that can be baz'd

Which of these two operations is better to use, and why?

like image 991
Vardarac Avatar asked Mar 18 '23 01:03

Vardarac


1 Answers

using gnar = grok.foo_attr2 && grok.foo_attr2.bar.baz will be definitely faster as it's done using Ruby's logical operator. While try is introduced by Rails and does additional if-else conditional checks. From code:

# File activesupport/lib/active_support/core_ext/object/try.rb, line 41
def try(*a, &b)
  if a.empty? && block_given?
    yield self
  else
    public_send(*a, &b) if respond_to?(a.first)
  end
end

Well, here's a benchmark to show exactly what I am trying to say:

class Object
  def try(*a, &b)
    if a.empty? && block_given?
      yield self
    else
      public_send(*a, &b) if respond_to?(a.first)
    end
  end
end

class Foo
  attr_reader :a
  def initialize(a = nil)
    @a = a    
  end
end

require "benchmark"


bar = Foo.new
baz = Foo.new(1)

n = 10000000
Benchmark.bm(40) do |x|
  x.report("try"){ n.times { bar.a.try(:class).try(:to_s) } }
  x.report("&& "){ n.times { baz.a && baz.a.class.to_s } }
end

Result is:

           user      system      total        real
try      10.800000  0.030000   10.830000  ( 10.829770)
&&        3.940000   0.010000   3.950000  (  3.944375)
like image 92
Surya Avatar answered Mar 23 '23 21:03

Surya