From: tomsonp@... (Phil Tomson) Date: 2005-10-30T11:17:06+09:00 Subject: Re: What would it take to change the behaviour of variable assignment? In article <28c4258c0510281349i4c1d69fbteb83f235d00b8d4a@mail.gmail.com>, Daniel Nugent wrote: >Hello, > >I've been considering the ways to add a particular language construct >(data flow variables) to Ruby. I've come up with, and implemented, >one method of doing this, but it relies on global variables (I >mentioned this on the list a month ago or so), so it's not something I >really want to stick with. > >Another way I've imagined doing it would involve changing the way >assignment works for instances of a Class while behaving more nicely. > >I'm envisioning something like this: > >foo =3D DataFlow.new > >bar =3D Thread.new(foo) {|fooinarr| print fooinarr[0]} >baz =3D Thread.new(foo) {|fooinarr| sleep(3);fooinarr[0] =3D "Hello World, >sorry I'm late"} > >Or, alternatively > >foo =3D DataFlow.new >Thread.new(foo) {|fooinarr| begin(fooinarr[0]} #Starts a time >consuming, but autonomous job >#Lots of user interaction >foo =3D gets >#Lots more interaction > >I know these examples aren't the greatest, but trust me, there's >better stuff you can do. > >In any case, to make this possible, it would require changing the way >that variabe assignment works. I realize that this isn't something >you can do in pure Ruby, but I'm curious if anyone knows of a way to >do it at all, possibly limiting the scope of the change to just >members of DataFlow so that they can act as wrappers for objects >assigned to foo. > You might want to take a look at RHDL ( http://www.aracnet.com/~ptkwt/ruby_stuff/RHDL/ ). HDL's are essentially dataflow langauges, I implemented an HDL using ruby (hence RHDL). Take a look at the Signal class defined there. They can accecpt values from different Processes which are running independently. Initially I had a similar problem with assignment. I resolved it by introducing an assign method on Signal's (or operator << for short). Note that process in this context is not an OS process, but I suppose they could be. Here's an example of a WashMachine state machine written in RHDL: #begin washmachine: require 'RHDL' class WashMachine < RHDL::Design include RHDL def initialize(clk,rst) super() state_sig = Signal(StateType(:start,:wash,:rinse,:spin,:stop)) define_behavior { process(clk,rst) { #async reset: if rst == '1' puts "RESET" state_sig << :start elsif clk.event && clk == '1' case state_sig.inspect when :start state_sig << :wash when :wash state_sig << :rinse when :rinse state_sig << :spin when :spin state_sig << :stop when :stop #stay here till reset else raise "invalid state! #{state_sig.state}" end end } process(state_sig) { #prints message whenever state_sig changes: puts "Current state is: #{state_sig}" } } end end if $0 == __FILE__ include RHDL include TestBench clk = ClkGen.generator('0',2,2) rst = Signal(Bit.new('1')) fsm = WashMachine.new(clk,rst) puts "step: 0" step puts "step: 1" step puts "step: 2" step rst << '0' 18.times do |i| puts "step: #{i+2}" step end rst << '1' 4.times do |i| puts "step: #{i+2+18}" step rst << '0' end end #end of washmachine Whenever the signal StateSig changes it causes the second process to be started. In this case the second process just prints the value of StateSig, but you could also do more with it. Oh, the first process is triggered whenever either clk or rst change. The arguments to 'process' are considered it's sensitivity list (in HDL parlance) meaning that the process is sensitive to any changes in the signals listed. You'll notice the ClkGen declaration down towards the end, that sets up the clk signal that toggles between 0 and 1 every 2 'cycles' - it's a 'free running' clock. This causes the first process to be triggered everyh time the clk signal changes. The rst signal is used to put the state machine into it's initial state. While RHDL is intended as an example of a hardware description language and simulator for said language and thus for hardware design, I think it also has potential for data-flow programming. Phil