• This repository has been archived on 07/Jul/2020
  • Stars
    star
    6
  • Rank 2,539,965 (Top 51 %)
  • Language
    Ruby
  • Created over 6 years ago
  • Updated over 6 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Micro gem for memoization on frozen objects

MemoizedOnFrozen

Build Status

Immutable objects are a good thing, but they can't use memoization:

class Rectangle
  def initialize(x, y)
    @x = x
    @y = y

    freeze
  end

  def area
    @area ||= @x * @y
  end
end

Rectangle.new(2, 3).area
# => FrozenError (can't modify frozen Rectangle)

This gem offers a very simple solution - it performs a memoization on a "global" registry object.

Like this:

def area
  $registry[self][:area] ||= @x * @y
end

But then we face another problem: memory leaking. Every object that is memoized creates a garbage in the "global" variable that is never GC-ed. This can be solved using WeakRef Ruby class.

MemoizedOnFrozen uses a Hash as a registry under the hood, but this hash uses WeakRefs as keys.

Example

Declare a class:

require 'memoized_on_frozen'

class Rectangle
  include MemoizedOnFrozen[:area]

  def initialize(x, y)
    @x = x
    @y = y

    freeze
  end

  def area
    puts 'calculating area'
    @x * @y
  end
end

And see how the library handles it:

rectangle1 = Rectangle.new(1, 2)
rectangle2 = Rectangle.new(3, 4)

rectangle1.area
# calculating area
# => 2
rectangle1.area
# => 2

rectangle2.area
# calculating area
# => 12
rectangle2.area
# => 12

MemoizedOnFrozen::WEAK_STORE.keys
# => [rectangle1, rectangle2]

rectangle1 = rectangle2 = nil
GC.start
MemoizedOnFrozen::WEAK_STORE.keys
# => []

You can find a working example in example.rb

Installation

Add this line to your application's Gemfile:

gem 'memoized_on_frozen'

Or if you'd like to use an alias Memoized instead of MemoizedOnFrozen (and you are 100% sure that there are no conflicts with existing classes):

gem 'memoized_on_frozen', require: 'memoized_on_frozen/as_memoized'

The file lib/memoized_on_frozen/as_memoized.rb literally does Memoized = MemoizedOnFrozen

And then execute:

$ bundle

Or install it yourself as:

$ gem install memoized_on_frozen

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/iliabylich/memoized_on_frozen.