I have a situation for Ruby, where an object is possibly necessary to be created, but it is not sure. And as the creation of the object might be costly I am not too eager creating it. I think this is a clear case for lazy loading. How can I define an object which is not created only when someone sends a message to it? The object would be created in a block. Is there a way for simple lazy loading/initialisation in Ruby? Are these things supported by some gems, which provide different solutions for various cases of lazy initialisation of objects? Thanks for your suggestions!
There are two ways.
The first is to let the caller handle lazy object creation. This is the simplest solution, and it is a very common pattern in Ruby code.
class ExpensiveObject
def initialize
# Expensive stuff here.
end
end
class Caller
def some_method
my_object.do_something
end
def my_object
# Expensive object is created when my_object is called. Subsequent calls
# will return the same object.
@my_object ||= ExpensiveObject.new
end
end
The second option is to let the object initialise itself lazily. We create a delegate object around our actual object to achieve this. This approach is a little more tricky and not recommended unless you have existing calling code that you can't modify, for example.
class ExpensiveObject # Delegate
class RealExpensiveObject # Actual object
def initialize
# Expensive stuff here.
end
# More methods...
end
def initialize(*args)
@init_args = args
end
def method_missing(method, *args)
# Delegate to expensive object. __object method will create the expensive
# object if necessary.
__object__.send(method, *args)
end
def __object__
@object ||= RealExpensiveObject.new(*@init_args)
end
end
# This will only create the wrapper object (cheap).
obj = ExpensiveObject.new
# Only when the first message is sent will the internal object be initialised.
obj.do_something
You could also use the stdlib delegate
to build this on top of.