Skip to content

Instantly share code, notes, and snippets.

@postmodern
Last active July 7, 2024 07:03
Show Gist options
  • Save postmodern/8db319b71a628ca23727e9a8c31e45e5 to your computer and use it in GitHub Desktop.
Save postmodern/8db319b71a628ca23727e9a8c31e45e5 to your computer and use it in GitHub Desktop.
Benchmarking if / else with kind_of? against case / in to match two values based on their classes. if / else + kind_of? appears to be 4x faster.
ruby 3.2.4 (2024-04-23 revision af471c0e01) [x86_64-linux]
Warming up --------------------------------------
if / else 888.000 i/100ms
case / in 259.000 i/100ms
Calculating -------------------------------------
if / else 8.856k (± 0.9%) i/s - 44.400k in 5.013974s
case / in 2.560k (± 3.0%) i/s - 12.950k in 5.064976s
#!/usr/bin/env ruby
require 'benchmark/ips'
class Foo
end
class Bar
end
value1 = Foo.new
value2 = Bar.new
Benchmark.ips do |b|
n = 1_000
b.report('if / else') do
n.times do
result = if (value1.kind_of?(Foo) && value2.kind_of?(Bar))
true
else
false
end
end
end
b.report('case / in') do
n.times do
result = case [value1, value2]
in [Foo, Bar]
true
else
false
end
end
end
end
@chastell
Copy link

chastell commented Jul 6, 2024

It seems to be only 2.7 times in Ruby 3.3, progress! But I think with the two arrays created on every iteration in case it’s hard to match the if direct method calls…

(I dropped the n.times iterations and added a b.compare! call for the below results.)

ruby 3.3.3 (2024-06-12 revision f1c7b6f435) [arm64-darwin23]
Warming up --------------------------------------
           if / else     1.343M i/100ms
           case / in   485.319k i/100ms
Calculating -------------------------------------
           if / else     13.398M (± 0.4%) i/s -     67.140M in   5.011198s
           case / in      4.919M (± 1.5%) i/s -     24.751M in   5.032843s

Comparison:
           if / else: 13398124.2 i/s
           case / in:  4919093.6 i/s - 2.72x  slower

@chastell
Copy link

chastell commented Jul 7, 2024

Ah yes, interstingly after doing

match = [Foo, Bar].freeze
# …
    case [value1, value2]
    in match
      true
    else
      false
    end

The results are almost the same:

ruby 3.3.3 (2024-06-12 revision f1c7b6f435) [arm64-darwin23]
Warming up --------------------------------------
           if / else     1.340M i/100ms
           case / in     1.307M i/100ms
Calculating -------------------------------------
           if / else     13.373M (± 0.6%) i/s -     67.014M in   5.011276s
           case / in     13.129M (± 0.5%) i/s -     66.674M in   5.078370s

Comparison:
           if / else: 13373168.5 i/s
           case / in: 13129463.4 i/s - 1.02x  slower

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment