Last active
April 1, 2021 17:42
-
-
Save JoshCheek/d52462e68225568e2729bb58a89e5f2e to your computer and use it in GitHub Desktop.
Example of how you could use Ruby's WeakRef to perform weak memoization
This file contains 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
require 'weakref' | |
# This module allows methods to be memoized, but the memoized result can still be GC'd. | |
# So the object can live for a long time. Eg maybe it's created on server initialization | |
# and lasts for the lifetime of a server. If the calculated result is large, | |
# then memoizing it doesn't permanently allocate that memory. | |
module WeakMemo | |
def memoize(name) | |
method = instance_method name | |
ivar = :"@_memoized_#{name}" | |
define_method name do | |
memoized = instance_variable_get ivar | |
return memoized.__getobj__ if memoized&.weakref_alive? | |
instance_variable_set ivar, WeakRef.new(method.bind_call(self)) | |
redo | |
end | |
name | |
end | |
end | |
# This class just has the pure logic for the calculation | |
Calculate = Struct.new :arg1, :arg2 do | |
extend WeakMemo | |
memoize def call | |
arg1 + arg2 # represents some arbitrary calculation | |
end | |
end | |
calc = Calculate.new 'a', 'b' | |
calc.call # => "ab" | |
# Returns the memoized object (same object id) | |
calc.call.object_id # => 60 | |
calc.call.object_id # => 60 | |
# But if the result has been GC'd, it recalculates it (new object id) | |
GC.start | |
calc.call.object_id # => 80 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment