Skip to content

Instantly share code, notes, and snippets.

@JoshCheek
Last active April 1, 2021 17:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JoshCheek/d52462e68225568e2729bb58a89e5f2e to your computer and use it in GitHub Desktop.
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
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