Lazy and Data Flow Variables REDUX!

D

Daniel Nugent

Hello again Rubyists,

Since my last correspondance on making Lazy evaluation and Data Flow
variables seamless in Ruby, there's been a breakthrough: I think I got
them all working right!

Code with contrived demos follows:

#Lazy Evaluation
#Dan Nugent and several persons from #ruby-lang (with special thanks
to interferon for showing me how to make data_flow not stupid)

#A class that generates lazy proxy objects.
#
#The crutch of lazy evaluation is that you don't do something UNTIL it's ne=
eded.
#Code generators work on this principle to create collections that
would otherwise
#be infinite series.
#
#This class doesn't let you create a code generator, but it does let you
#avoid evaluating expensive code blocks until you absolutely,
positively, need to
#kill every mot... errr, absolutely need to. Just like call by name evalua=
tion!
class Lazy

=09#DESTROY ALL METHODS! DESTROY ALL INSTANCE METHODS!
=09instance_methods.each { |m| undef_method m unless m =3D~ /^__/ }

=09#The optional parameter switch allows you to define whether you'd like
=09#the object to evaluate the block once and save its value or repeatedly =
call
=09#the block every time a method is called against the Lazy object
=09#
=09#This option is present in the other two lazy lambda generators
=09def initialize(switch =3D :eek:ne_eval, &block)
=09=09@code_block =3D block
=09=09@mode =3D switch
=09end

=09def method_missing(symbol, *args)
=09=09if @mode =3D=3D :eek:ne_eval
=09=09=09@real_obj ||=3D @code_block.call
=09=09=09@real_obj.__send__(symbol, *args)
=09=09else
=09=09=09@code_block.call().__send__(symbol, *args)
=09=09end
=09end
end

#Use this function (functor?) to do lazy evaluation of a code block

def lazy(switch =3D :eek:ne_eval, &block)
=09Lazy.new(switch, &block)
end

#Use this one to create a data flow variable (or data flow code-block
or whatever)
#
#A warning: If the passed block is an expensive operation or if nil or
false are valid
#return values of your block, you should define a custom conditional.=20
The default
#conditional repeatedly calls the block to determine if it is a
defined value yet.
#This is a bad thing in the case of either an expensive block or a
return value of nil
#or false
#
#However, most of the time, you can just leave it be.

def data_flow(cond =3D nil, switch =3D :eek:ne_eval, &block )
=09cond ||=3D lambda {block.call}
=09lazy(switch) do
=09=09until cond.call
=09 =09=09Thread.pass
=09=09end
=09=09block.call
=09end
end

##BEGIN CONTRIVED DEMO##
=3Dbegin
foo =3D data_flow{$dfv}

bar =3D Thread.new {print foo}
baz =3D Thread.new {sleep(3);$dfv =3D "Hello World, sorry I'm late"}

bar.join
baz.join
=3Dend

##AN EVEN MORE CONTRIVED, COUNTER-INTUITIVE (BUT FUNNIER) DEMO##
#This isn't a very practical example, but it demonstrates a (silly) reason
#you may want to allow the block to be evaluated multiple times

=3Dbegin
season =3D data_flow(nil,:mult){$season}

elmer =3D Thread.new do
=09=09#Here, we see the nice thing about the data flow variables.
=09=09#These threads aren't hogging resources in idle loops=20
=09=09#because they keep passing the buck back to the scheduler=20
=09=09#until there's something to do.
=09=09until season.match("FIRE")
=09=09=09print season + "\n"
=09=09=09$season =3D nil
=09=09end
=09=09print season + "\n"
=09=09print "BLAM!"
=09end

bugsanddaffy =3D Thread.new do
=09=093.times do
=09=09=09$season =3D "Bugs: Duck Season!"
=09=09=09sleep(0.6)
=09=09=09$season =3D "Daffy: Wabbit Season!"
=09=09=09sleep(0.6)
=09=09end
=09=09$season =3D "Bugs: Wabbit Season!"
=09=09sleep(0.6)
=09=09$season =3D "Daffy: Duck Season!"
=09=09sleep(0.6)
=09=09$season =3D "Bugs: Wabbit Season!"
=09=09sleep(0.6)
=09=09$season =3D "Daffy: I say it's DUCK season, and I say..."
=09=09sleep(2.2)
=09=09$season =3D "FIRE!"
=09end

elmer.join
bugsanddaffy.join
=3Dend

If you want to try my silly and contrived demos, be sure to get rid of
the =3Dbegin and =3Dend. Otherwise, it should just run from the command
line.
--=20
-Dan Nugent
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,236
Members
46,822
Latest member
israfaceZa

Latest Threads

Top