Change prepend MemoWise
to extend MemoWise
#253
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.
Co-authored-by: Jemma Issroff [email protected]
What the refactor does:
The only public facing change in this refactor is that instead of
prepend MemoWise
, clients will nowextend MemoWise
. Internally, this refactor simplifies the machinery necessary to get memoization working, including eliminating back and forth of singleton classes and deferring definitions ofpreset_memo_wise
andreset_memo_wise
. With this change, MemoWise will also no longer redefine methods, simplifying delegation to the original method and making it easier to determine which methods are memoized.Guiding principles for the refactor:
MemoWise
module should be as nonintrusive as possible. By utilizingextend
, we make sure that mixing inMemoWise
only adds thememo_wise
method on the the class, which is the main API of the library.initialize
) and eagerly defines many instance variables on the mixin site, thus unnecessarily polluting the target.ObjectSpace
to find attached objects to singleton classes, or the library needs to keep checking if the mixin site is a singleton class or not.super
to delegate to the actual instance. Moreover, this method of prepended methods plays nicer with other forms of method wrapping that other libraries could be using as well (for example, in its current form MemoWise would not play nicely with Sorbet runtime).How the refactor works:
Step 1. Call
extend MemoWise
from a class/module.This exposes the method
memo_wise
to the class/module as a class method.Step 2. Call the
memo_wise
method on an instance method (for example,memo_wise :example_method
).With the first
memo_wise
method call, a module namedMemoWiseMethods
is created. This module haspreset_memo_wise
,reset_memo_wise
andfreeze
as instance methods. Thememo_wise
call also adds a memoized shadow instance method on this module (for example,MemoWiseMethods#example_method
).Step 3. The
MemoWiseMethods
module is automaticallyprepend
ed on the original class/module.The use of
prepend
means that the shadow methods on this module take precedence over the original methods. Callingsuper
from within the shadow methods is sufficient for accessing the original methods (instead of doing the "alias-method-chain" dance).Notes:
memo_wise
on class methods makes the singleton class of the class/moduleextend MemoWise
, and callsmemo_wise
for the instance methods on the singleton class. Accordingly,preset_memo_wise
andreset_memo_wise
are only defined as class methods the first timememo_wise
is called on a class method (withself:
).freeze
method and initializing internal state before callingsuper
.Before merging:
README.md
and update this PRCHANGELOG.md
, add an entry following Keep a Changelog guidelines with semantic versioning