From: Daniel Nugent Date: 2005-09-08T14:57:29+09:00 Subject: The Laziest Variable in the Whooole World Hello fellow Rubyists, Something got to niggling me in the back of my mind last week during a lecture in my Programming Languages class about laziness in functions. Basically, the point is that functions that don't evaluate until they need to are cool. We can be pretty lazy right now with code generators that will let us fake infinite series and stuff like that, but I think we can be even LAZIER if we put our minds to it. Along these lines, I came up with this: class Lazy #DESTROY ALL METHODS! DESTROY ALL INSTANCE METHODS! instance_methods.each { |m| undef_method m unless m =~ /^__/ } def initialize(switch = :one_eval, &block) @code_block = block @mode = switch end def method_missing(symbol, *args) if @mode == :one_eval @real_obj ||= @code_block.call @real_obj.__send__(symbol, *args) else @code_block.call().__send__(symbol, *args) end end end What this does is let us wait until a value is really, actually needed before the code that would provide it is evaluated. This is nice if you wanted to put off that expensive retrieval operation until it was actually needed, if at all, and if you're tricky about it, you can get non-deterministic results just like the bastiche you want to be (just set the switch to something besides :one_eval, now the block is called ALL the time!). With a little bit of tricksyness, we can use this to let us turn regular variables into dataflow variables, which, instead of causing all sorts of errors because they're not ready yet, merely make the program wait until they're darned well not nil (or whatever condition you happen to need). For example: #Dataflow example foo = Lazy.new do while $data_flow_variable.nil? end $data_flow_variable end bar = Thread.new {print foo} baz = Thread.new {sleep(3);$dfv = "Hello World, sorry I'm late"} bar.join baz.join This is, of course, trivial, but it demonstrates how you might employ data flow for fun and profit (Especially if you could abstract laziness and dataflowism into functions that did all the boring object creation work for you, which, of course, you could). The question, of course, is where are the gaps here? Where does this idea just fall apart and spew, SPEW all over the floor? I'm reasonably sure you're all much more masterful at Ruby than I am and stand a better chance at figuring out what could explode (I personally expect that assignment will botch it up, but I can't be sure.) And, if explosion is imminent, can it be fixed? Thanks for reading! PS: Thanks to Aria and binary42 for smacking me around a little and pointing me to {|one, step, back|} and the BlankSlate idea there. -- -Dan Nugent