Skip to content

Memoize merged enum hashes to fix superclass-lookup performance regression - #60

Merged
dblock merged 1 commit into
masterfrom
memoize-enum-hash
Aug 15, 2026
Merged

Memoize merged enum hashes to fix superclass-lookup performance regression#60
dblock merged 1 commit into
masterfrom
memoize-enum-hash

Conversation

@dblock

@dblock dblock commented Aug 15, 2026

Copy link
Copy Markdown
Owner

What

Benchmarking the superclass-inheritance work from #59 surfaced a performance regression: keys, key?, value?, key, value, to_h, parse, each, each_key, and each_value now walk and merge the entire superclass chain on every call, with no caching. On a 1-level subclass this made .value ~5x slower and .keys ~3x slower than the base class.

Fix

  • Memoize _enum_hash/_enums_by_value, invalidating the cache in store_new_instance (i.e. on define) so newly defined enums are always reflected.
  • Disable Metrics/ModuleLength (module grew past the default 100-line limit purely due to the extra memoization/invalidation lines).
  • Add benchmarks/inheritance.rb + rake benchmark:inheritance task to track this going forward.
  • Fix README, which documented the case benchmark task as rake benchmarks:case (doesn't exist) instead of the actual rake benchmark:case.

Before / After (1,000,000 iterations, 1-level subclass)

before after
SubColors.value 0.253s (~5x base) 0.061s (~1x base)
SubColors.keys 0.358s 0.178s

Testing

  • bundle exec rake (rubocop + rspec): 69 examples, 0 failures, rubocop clean (24 files)
  • 100% line coverage maintained
  • spec_i18n suite: 3 examples, 0 failures
  • rake benchmark:inheritance run manually to confirm the fix

@github-actions

github-actions Bot commented Aug 15, 2026

Copy link
Copy Markdown

Danger Report

Warnings

  • Unless you're refactoring existing code or improving documentation, please update CHANGELOG.md.

Markdowns

Here's an example of a CHANGELOG.md entry:

* [#60](https://github.com/dblock/ruby-enum/pull/60): Memoize merged enum hashes to fix superclass-lookup performance regression - [@dblock](https://github.com/dblock).

View run

Fix a performance regression introduced when keys, key?, value?, key,
value, to_h, parse and each were made to walk the superclass chain:
every call was recomputing the merged hash from scratch instead of
caching it, making these methods significantly slower on subclasses.

- Memoize _enum_hash/_enums_by_value, invalidating on define.
- Disable Metrics/ModuleLength rubocop cop (module grew past the
  default 100-line limit due to the memoization).
- Add benchmarks/inheritance.rb covering base/subclass/sub-subclass
  .value lookups plus .keys, .key?, .to_h and .each on a subclass,
  and a rake benchmark:inheritance task.
- Fix README documenting the case benchmark task as
  'rake benchmarks:case' instead of the actual 'rake benchmark:case'.

Co-authored-by: Copilot <[email protected]>
@dblock
dblock force-pushed the memoize-enum-hash branch from 7bd68a9 to 6c22990 Compare August 15, 2026 01:54
@dblock
dblock merged commit 82457aa into master Aug 15, 2026
22 checks passed
@dblock
dblock deleted the memoize-enum-hash branch August 15, 2026 01:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant