I have often wanted to execute a bit of code only if the result of
that code is used later. For example in a Rails app I might load some
data in my controller but sometimes depending on some situations the
result is not actually used in the view.
So what I want is to be able to do:
@recent = lazy { Post.find_recent 5 }
But then if @recent is never used the actual search is not executed.
But because I don’t want to break compatibility once @recent is used I
want it to act and behave exactly like it is the return value of the
block. Even the core methods like class and respond_to? should return
the correct values.
So I took my first stab at it. You can see it at:
http://files.pixelwareinc.com/transparent_lazy.rb
My questions are:
- What trouble am I getting myself into by allowing this object to
completely loose it’s identity? - What holes are in the armor? Is there any way my proxy class does
not act like the result of the block? If there are, do they matter? - What are the performance and memory implications?
The only hole I can think of is that you see the proxy if you are
stepping through your code. This is no big deal to me.
There would be a slight memory increase as there is an extra object
but it should be insignificant. And everything should be garbage
collected when nothing is using the proxy object anymore so I don’t
forsee any memory leaks. Obviously every call to the lazy-loaded data
incurs an extra method call but I think I can live with that.
My next step will be to monkey-patch this into Rails so that
ActiveRecord::Base.find will use the lazy method by default. This will
allow everything to be lazy loaded without having to change a single
line of code in my application.