TIL - Use Struct over OpenStruct for performance

TL;DR Struct is much faster than OpenStruct.

I learned this while contributing to Gitlab.

There has already been written about Struct and OpenStruct. But this post focuses on the performance implications of using one over other.

Developers have tendency to use OpenStruct over Struct generally because with OpenStruct, we can arbitrarily set & access attributes. However, in case of Struct, we can only set & access attributes defined at the time of Struct declaration.

e.g.,

Here is a quick benchmark report performed on MacOS taken from Gabriel Mazetto’s comment on Gitlab for quick reference:

Ruby 2.7.2

Warming up --------------------------------------
      openstruct new   138.338k i/100ms
   openstruct access     6.255k i/100ms
          struct new   300.884k i/100ms
      struct acccess   240.079k i/100ms
Calculating -------------------------------------
      openstruct new      1.409M (± 2.1%) i/s -      7.055M in   5.008396s
   openstruct access     62.552k (± 3.6%) i/s -    312.750k in   5.007322s
          struct new      3.032M (± 1.8%) i/s -     15.345M in   5.063488s
      struct acccess      2.397M (± 1.4%) i/s -     12.004M in   5.008534s

Comparison:
          struct new:  3031505.6 i/s
      struct acccess:  2397159.8 i/s - 1.26x  (± 0.00) slower
      openstruct new:  1409319.1 i/s - 2.15x  (± 0.00) slower
   openstruct access:    62551.7 i/s - 48.46x  (± 0.00) slower

Ruby 3.0.0

Warming up --------------------------------------
      openstruct new     5.654k i/100ms
   openstruct access     4.880k i/100ms
          struct new   298.290k i/100ms
      struct acccess   237.080k i/100ms
Calculating -------------------------------------
      openstruct new     57.811k (± 1.7%) i/s -    294.008k in   5.087150s
   openstruct access     49.124k (± 2.1%) i/s -    248.880k in   5.068713s
          struct new      2.972M (± 1.7%) i/s -     14.914M in   5.020725s
      struct acccess      2.363M (± 3.0%) i/s -     11.854M in   5.022310s

Comparison:
          struct new:  2971520.7 i/s
      struct acccess:  2362714.6 i/s - 1.26x  (± 0.00) slower
      openstruct new:    57811.0 i/s - 51.40x  (± 0.00) slower
   openstruct access:    49123.9 i/s - 60.49x  (± 0.00) slower

You can see here OpenStuct is 60 times slower than Struct.

Even OpenStuct can be slower than Hash in some cases. From the Ruby doc,

Creating an open struct from a small Hash and accessing a few of the entries can be 200 times slower than accessing the hash directly.

Go for Struct whenever possible over OpenStruct.