Issue #16243 has been updated by nobu (Nobuyoshi Nakada).


Interesting.
I tried a couple approaches, but couldn't get significant results.
* `checkmatch` with call cache
  https://github.com/nobu/ruby/pull/new/feature/checkmatch-cache
* replace simple `checkmatch` with `:=3D=3D=3D` call
  https://github.com/nobu/ruby/pull/new/feature/checkmatch-to-send

----------------------------------------
Bug #16243: case/when is slower than if on MRI
https://bugs.ruby-lang.org/issues/16243#change-81933

* Author: Eregon (Benoit Daloze)
* Status: Open
* Priority: Normal
* Assignee: =

* Target version: =

* ruby -v: ruby 2.6.5p114 (2019-10-01 revision 67812) [x86_64-linux]
* Backport: 2.5: UNKNOWN, 2.6: UNKNOWN
----------------------------------------
This comes from a discussion on a PR on Sidekiq: https://github.com/mperham=
/sidekiq/pull/4303

This benchmark:
```ruby
# frozen_string_literal: true
require "benchmark/ips"

def deep_dup_case(obj)
  case obj
  when Integer, Float, TrueClass, FalseClass, NilClass
    obj
  when String
    obj.dup
  when Array
    obj.map { |e| deep_dup_case(e) }
  when Hash
    duped =3D obj.dup
    duped.each_pair do |key, value|
      duped[key] =3D deep_dup_case(value)
    end
  else
    obj.dup
  end
end

def deep_dup_if(obj)
  if Integer =3D=3D=3D obj || Float =3D=3D=3D obj || TrueClass =3D=3D=3D ob=
j || FalseClass =3D=3D=3D obj || NilClass =3D=3D=3D obj
    obj
  elsif String =3D=3D=3D obj
    obj.dup
  elsif Array =3D=3D=3D obj
    obj.map { |e| deep_dup_if(e) }
  elsif Hash =3D=3D=3D obj
    duped =3D obj.dup
    duped.each_pair do |key, value|
      duped[key] =3D deep_dup_if(value)
    end
    duped
  else
    obj.dup
  end
end


obj =3D { "class" =3D> "FooWorker", "args" =3D> [1, 2, 3, "foobar"], "jid" =
=3D> "123987123" }

Benchmark.ips do |x|
  x.report("deep_dup_case") do
    deep_dup_case(obj)
  end

  x.report("deep_dup_if") do
    deep_dup_if(obj)
  end

  x.compare!
end
```

gives in MRI 2.6.5:
```
Warming up --------------------------------------
       deep_dup_case    37.767k i/100ms
         deep_dup_if    41.802k i/100ms
Calculating -------------------------------------
       deep_dup_case    408.046k (=B1 0.9%) i/s -      2.077M in   5.090997s
         deep_dup_if    456.657k (=B1 0.9%) i/s -      2.299M in   5.035040s

Comparison:
         deep_dup_if:   456657.4 i/s
       deep_dup_case:   408046.1 i/s - 1.12x  slower
```

It seems @tenderlovemaking already noticed this a while ago due to missing =
inline caches for `case`, but the performance bug seems to still remain:
https://youtu.be/b77V0rkr5rk?t=3D1442

Do you think this could be fixed in MRI?
AFAIK both JRuby and TruffleRuby support inline cached `=3D=3D=3D` calls in=
 `case/when`.

I think the code with `case` is more idiomatic and readable and should be p=
referred to `if`, and this performance issue makes that less clear.

---Files--------------------------------
case_vs_if.rb (1003 Bytes)


-- =

https://bugs.ruby-lang.org/

Unsubscribe: <mailto:ruby-core-request / ruby-lang.org?subject=3Dunsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>