0

I have a class whose initialize method gets data from a remote source, which it then uses to set its object attributes.

I'm expecting this class to be heavily used, possibly hundreds of times within a program. I'd like to reduce the overhead network calls by caching objects that have already been instantiated, which I'd then return to the user when they ask to instantiate that object again.

For that, I've been considering overriding the new method for this class. It would check to see if the cached object is available, and if so, return that reference. Otherwise, it would call the regular new method for the object, which would allocate memory and call initialize like usual.

If I override the new() method in a class, is it possible to call the original new method via something like super()?

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
dsw88
  • 4,400
  • 8
  • 37
  • 50

2 Answers2

3

Yes, super without parameters will call the parent method with the same parameters passed to the new method.

Or, you can cherry-pick parameters by adding them to super(p1, p2, ...).

Regarding what you want to do by remembering previous invocations, that's called "memoizing" and there is at least one memoize gem for it, or, you can write your own, depending on your needs.

It's pretty easy to do using a hash. Use the parameters used when invoking the new method as the key, and the value is the instance you want to return. Without examples of your code it's hard to come up with an example that's custom-fit, but this is a simple, untested, version:

def initialize(*args)
  @memoizer ||= {}
  return @memoizer[args] if @memoizer[args]
  # do what you will with the args in this initializer, 
  # then create a new instance for the future.
  @memoizer[args] = super(args)
end

The idea is that @memoizer remembers the "arity" of the call and automatically returns the result of similar calls. If that set of parameters haven't been seen before it'll compute and create the new instance and then return it.

This breaks down when the result could change with the same set of input parameters. You don't want to memoize database calls or anything using random or a date/time value, or that returns something outside your control. Trying to use it in those cases will return stale or wrong values unless you design in a method to sweep through and revalidate the @memoizer values periodically.

Also, there is no flushing mechanism, so @memoizer will only grow in size, and could possibly consume all available space given enough different input values. To deal with that you could also have a timestamp for when the value was added to @memoizer, and periodically purge entries that exceed a given lifetime. Only "live" values would remain in the hash then.

Useful information is at: "Memoize Techniques in Ruby and Rails".

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
  • Thanks for the help! Here's my override code then, will this break anything? `def self.new(*args) # Check whether to return a memoized object # If no object exists, then instantiate a new object super(*args) end` – dsw88 Apr 19 '13 at 20:01
1

either via super or via an alias_method chain

super is better if you sub-class

Check this: When monkey patching a method, can you call the overridden method from the new implementation?

Community
  • 1
  • 1
Tilo
  • 33,354
  • 5
  • 79
  • 106