I want to avoid reevaluation of a value in method call. Untill now, I was doing this:
def some_method
@some_method ||= begin
# lot's of code
end
end
But it ends up quite ugly. In some code, I saw something like the following:
def some_method
@some_method ||= some_method!
end
private
def some_method!
# lot's of code
end
I don't like the bang (!
) at the end, so I came up with this:
def some_method
@some_method ||= _some_method
end
private
def _some_method
# lot's of code
end
- Is prepending with an underscore a good convention?
- Is there some other convention for memoized/non-memoized pairs of methods?
- Is there some convention to memoize multi-line methods?
There is one more way, more Java-style I think.
First of all you should implement annotations, like "Java-style annotations in Ruby" and "How to simulate Java-like annotations in Ruby?".
Then you should add annotation like _cacheable that will said to method that it should return instance variable and if it is null it should calculate it by invoking method, so your code will be more clear:
I usually use
begin, end
as per your first example, but if there's a bit more code, I just look if the variable exists, no need to create another method just for that.I don't like the bang either. I use
Here
eval
is shorthand forevaluation
. I like the way this reads and also that it makes the public interface concise.I despise conventions that rely on underscores as distinguishing marks: they are both error prone and require that I remember YAMC (yet another meaningless convention). The Ada language, designed for safety-critical applications, does not allow leading, trailing, or multiple underscores. Nice idea.
I normally do it like in Agis answer or:
BTW:
I often use this memoization technique:
Which will allow you to later clear all memoized variables with one simple
@_memo.clear
. The @_memo variable should be initialized like thisHash.new { |h, k| h[k] = Hash.new }
. It gives you many of the adventages of using ActiveSupport::Memoize and similar meta programmed techniques which might be much slower.I would do it like this:
So I'd just name the method differently, as I think it makes more sense.
I use the memoist gem, which lets you easily memoize a method without having to alter your original method or create two methods.
So for example, instead of having two methods,
file_size
andcalculate_file_size
, and having to implement the memoization yourself with an instance variable:you can just do this:
Each memoized function comes with a way to flush the existing value.
So calling
object.file_size(true)
would be the equivalent of callingobject.calculate_file_size
...