ostruct
                                
                                
                                
                                    ostruct copied to clipboard
                            
                            
                            
                        Avoid defining singleton methods
This PR only creates new singleton methods when they are needed for overwriting an existing instance method. It should be mostly backward-compatible with the current OpenStruct implementation, but I suspect there are some minor incompatibilities (which may be significant).
I believe this should generally be a significant performance improvement. I'm guessing that OpenStruct objects are generally ephemeral and their attributes are generally read fewer than a dozen times on average. In my benchmarks, that wasn't enough for the benefits of defining singleton methods to outweigh the costs. All of the benchmarks I created, except for 100x reads, showed the same or better performance.
And that's mostly ignoring any non-local costs to constantly busting method caches. This PR should almost completely remove that cost.
$ benchmark-driver benchmarks/ostruct.yml
Warming up --------------------------------------
                  new     7.047k i/s -      7.711k times in 1.094212s (141.90μs/i)
      attr_write_read     4.904k i/s -      4.910k times in 1.001289s (203.93μs/i)
index_write_attr_read     6.346k i/s -      6.963k times in 1.097167s (157.57μs/i)
           null_reads    79.488k i/s -     85.250k times in 1.072495s (12.58μs/i)
            10x_reads     6.651k i/s -      7.282k times in 1.094836s (150.35μs/i)
           100x_reads     5.136k i/s -      5.150k times in 1.002780s (194.71μs/i)
Calculating -------------------------------------
                          v0.6.0       local
                  new     6.938k     33.067k i/s -     21.141k times in 3.047342s 0.639334s
      attr_write_read     4.886k     14.021k i/s -     14.711k times in 3.010686s 1.049232s
index_write_attr_read     6.270k     20.225k i/s -     19.039k times in 3.036489s 0.941373s
           null_reads    78.351k     77.187k i/s -    238.462k times in 3.043491s 3.089414s
            10x_reads     6.518k     13.306k i/s -     19.953k times in 3.061390s 1.499576s
           100x_reads     4.454k      2.078k i/s -     15.407k times in 3.459125s 7.414447s
Comparison:
                               new
                local:     33067.2 i/s
               v0.6.0:      6937.5 i/s - 4.77x  slower
                   attr_write_read
                local:     14020.7 i/s
               v0.6.0:      4886.3 i/s - 2.87x  slower
             index_write_attr_read
                local:     20224.7 i/s
               v0.6.0:      6270.1 i/s - 3.23x  slower
                        null_reads
               v0.6.0:     78351.5 i/s
                local:     77186.8 i/s - 1.02x  slower
                         10x_reads
                local:     13305.8 i/s
               v0.6.0:      6517.6 i/s - 2.04x  slower
                        100x_reads
               v0.6.0:      4454.0 i/s
                local:      2078.0 i/s - 2.14x  slower