Repository navigation
Conversation
`x@name` reaches `@.S7_object` through S3 dispatch on `class(x)`, which misses once per inheritance level before it finds the method. Register the same method (`prop()`) under each packaged class's own name so the first lookup hits and the cost of `@` no longer grows with class depth. `new_class()` registers the method and records the class name in the package's S3 methods table, which is saved with the package. `S7_on_load()` re-registers recorded classes and `S7_on_unload()` removes them. Classes without a package are not registered, and an existing `@` method is never replaced. Adds bench/property-access.R. 1000 reads, before -> after: depth 2 610 us -> 460 us (1.3x), depth 5 790 us -> 460 us (1.7x), depth 8 1.0 ms -> 460 us (2.2x).
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #723 (hot paths found while profiling CVXR, whose S7 class hierarchies go up to eight levels deep).
x@namereaches@.S7_objectthrough S3 dispatch onclass(x), which misses once per inheritance level before it finds the method. This PR registers the same method (prop()) under each packaged class's own name, so dispatch hits on the first lookup and the cost of@no longer grows with class depth. Behavior is unchanged: it is the same method.new_class()registers the method and records the class name in the package's.__S3MethodsTable__., which is saved with the package (as S7 already does for external methods).S7_on_load()re-registers recorded classes, andS7_on_unload()removes them.@method is never replaced, and R < 4.3 is untouched.Benchmark (
bench/property-access.R, 1000 reads per iteration, separate sessions before and after, R 4.6.1, macOS arm64):prop()andattr()timings are unchanged. The remaining gap between@andprop()(~200 µs per 1000 reads) is the fixed cost of base R's S3 dispatch for@, which S7 can't avoid.Trade-off to weigh: this adds one entry per packaged S7 class to base R's S3 methods table, managed by the load and unload hooks. If you'd rather not touch that table, the alternative is documenting
prop()as the fast spelling for hot paths.Tests: new tests in
test-hooks.Rcover registration, no-package classes, not replacing an existing method, load/unload, and an installed package. The full suite passes.