In JavaScript, it is fairly simple to memoize a function like Fibonacci:
// In JavaScript
var fibonacci = (function () {
var cache = {}; // cache for future calculations
return function (num) {
if (num < 0) throw new Error('Negative numbers not allowed');
if (num === 0) return 0;
if (num === 1) return 1;
cache[num] = cache[num] || fibonacci(num - 1) + fibonacci(num - 2);
return cache[num];
};
})();
console.log( fibonacci(5) ); // results in 5
console.dir( fibonacci ); // you can inspect the closure scope and see that the cache object saves the values for future use
I'm trying to understand how to do something similar in Ruby and unfortunately, the only thing I can come up with is creating a class and storing the cache as a class variable:
# In Ruby
class Placeholder
@@cache = {}
def fibonacci(num)
raise 'Negative numbers not allowed' if num < 0
return 0 if num == 0
return 1 if num == 1
@@cache[num] ||= fibonacci(num - 1) + fibonacci(num - 2)
end
end
example = Placeholder.new
puts example.fibonacci(5) # results in 5
What I don't like about this is the fact that I'm creating a class structure when I don't really intend to create instances of Placeholder. Instead, I'm only doing this because I want to save the state in a Ruby class variable. Ideally, if I were able to create a module and have a module variable, then that would at least solve my "problem" of instantiation with the class based solution. What are your best suggestions for doing this in Ruby?
Update based on @meagar's comment:
@meagar, are you suggesting something like this?
class Placeholder
attr_reader :cache
def initialize
@cache = {}
end
def fibonacci(num)
raise 'Negative numbers not allowed' if num < 0
return 0 if num == 0
return 1 if num == 1
@cache[num] ||= fibonacci(num - 1) + fibonacci(num - 2)
end
end
FibonacciCalculator = Placeholder.new
puts FibonacciCalculator.fibonacci(5) # results in 5
I already like this better than my initial Ruby solution, although having the Placeholder class still rubs me the wrong way.
staticwhen in a function, right?staticaddresses my questionPlaceholder; use arrays, not objects; use||=to memoize when possible; use<do something> if <condition>, neverif <condition> then do something; end.