Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Decorate .instance_method to proxy original params #163

Merged
merged 1 commit into from Jun 10, 2021
Merged

Conversation

ms-ati
Copy link
Contributor

@ms-ati ms-ati commented May 26, 2021

In Panorama spec helper code 'initialized_double', we observed
that MemoWise interrupts the use of Ruby reflection on method
parameters, by replacing with delegating methods that have overly
generic signatures, like:

def initialize(...)

def slow_method(*arg, **kwargs)

After investigation, we had determined that it was not worth
the complexity cost, and potential fragility, to pursue a solution
where we re-create the original method parmeter signatures for our
delegating implementations.

This PR is a minimalistic alternative, which narrowly overrides only
the implementation of {Module#instance_method} so that, in the case
of either #initialize or a method that has had .memo_wise called on it,
we look up the original method and proxy the original result value of
calling UnboundMethod#parameters on it.

@codecov
Copy link

codecov bot commented May 26, 2021

Codecov Report

Merging #163 (6f6676a) into main (c0c770f) will not change coverage.
The diff coverage is 100.00%.

❗ Current head 6f6676a differs from pull request most recent head 48ff701. Consider uploading reports for the commit 48ff701 to get more accurate results
Impacted file tree graph

@@            Coverage Diff            @@
##              main      #163   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files            1         1           
  Lines          123       134   +11     
=========================================
+ Hits           123       134   +11     
Impacted Files Coverage Δ
lib/memo_wise.rb 100.00% <100.00%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update bcd78d7...48ff701. Read the comment docs.

@ms-ati
Copy link
Contributor Author

ms-ati commented May 28, 2021

Re: #165

lib/memo_wise.rb Show resolved Hide resolved
lib/memo_wise.rb Outdated

orig_method =
if symbol == :initialize
curr_method.super_method
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fact that this evaluates to super.super_method is kind of confusing to me. Would you mind adding some comments here for what this is doing and why we need to special-case it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll add explicit documentation of the three paths:

  1. initialize - call super which is the original implementation of Module#instance_method, get back the UnboundMethod which represents our MemoWise version of initialize -- then ask it for #super_method, because it know the original method that it is overriding

  2. Any memo-wised method - we need to look up the original method by it's renamed symbol, and call super which is the original implementation of instance_method, using that name

  3. Anything else - we have orig_method = nil

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Modified per @jemmaissroff above and documented per this discussion, please re-review?

lib/memo_wise.rb Outdated
super(original_memo_wised_name)
end

unless orig_method.nil?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a comment explaining when orig_method will be nil? Is it just when there's no initialize method defined?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll clarify the cases -- just returning curr_method when it was not a memo_wised method and not initialize -- can make it clearer

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please re-review

lib/memo_wise.rb Outdated Show resolved Hide resolved
Copy link
Member

@JacobEvelyn JacobEvelyn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM if you add more documentation.

spec/proxying_original_method_params_spec.rb Show resolved Hide resolved
lib/memo_wise.rb Show resolved Hide resolved
lib/memo_wise.rb Show resolved Hide resolved
@@ -404,7 +404,7 @@ def #{method_name}#{args_str}
end

unless target.singleton_class?
# Create certain class methods to implement .preset_memo_wise
# Create class methods to implement .preset_memo_wise and .reset_memo_wise
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unrelated comment clarification

lib/memo_wise.rb Outdated
# to proxy the original `UnboundMethod#parameters` results. We want the
# parameters to reflect the original method in order to support callers
# who want to use Ruby reflection to process the method parameters,
# because the generated memoized method would have a generic set of
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you mind tweaking this to say something like ... because our overridden #initialize method, and in some cases the generated memoized methods, would have ...? (I'm also fine with being more vague—just wanted to flag that it's not always memoized methods and the args aren't always generic.)

Not sure if you're aware but avoiding generic params like *args in many cases is how @jemmaissroff and I got some big speedups recently.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed as requested!

In Panorama spec helper code 'initialized_double', we observed
that MemoWise interrupts the use of Ruby reflection on method
parameters, by replacing with delegating methods that have overly
generic signatures, like:

    def initialize(...)

    def slow_method(*arg, **kwargs, &block)

After investigation, we had determined that it was not worth
the complexity cost, and potential fragility, to pursue a solution
where we fully re-create the original method parameter signatures
in our delegating implementations.

However, we had decided to explore a more minimalistic alternative.

This PR is a minimalistic alternative, which narrowly overrides only
the implementation of {Module#instance_method} so that, in the case
of either #initialize or a method that has had .memo_wise called on it,
we look up the original method and proxy the original result value of
calling UnboundMethod#parameters on it.
@ms-ati ms-ati merged commit d26b1c1 into main Jun 10, 2021
@ms-ati ms-ati deleted the proxy-method-params branch June 10, 2021 20:12
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.

None yet

3 participants