On 20/11/2013, at 1:52 AM, srean wrote: > > What bugs me is that its not easy to convince people that callbacks is bad. > > "oh you just have to document them well..." > > Yes, its hard. I should write an article on it. > > I ask people to do this: > > Compute a + b *(c + d) using only the functions add(x,y) and mult(x,y) that > return a value. > > Now do it again with these functions that dont return a value but take a > callback cb that is called on the result: > > add(x, y, cb) > mult(x, y, cb) > and lambda > > People struggle with it, not that it convinces them, "my program will never > have to do anything like that" > > You can do all of this manually to make a callback driven system drive any > logic > you want ... > > .. but is a hell of a lot easier to get Felix to do it for you :) > > Indeed.
And if you'll excuse posting private email on the list ... here's the solution using Felix: //////////////////////////////////////////////////////////////////////////////////// // fthread examples // channels typedef ich = ischannel[int]; typedef och = oschannel[int]; gen mk () => mk_ioschannel_pair[int] (); // addition proc add (o:och, i1:ich, i2:ich) { var x = read i1; var y = read i2; write$ o,x + y; } // multiplication proc mul (o:och, i1:ich, i2:ich) { var x = read i1; var y = read i2; write$ o,x * y; } // a + b * (c + d) // // tmp1 = c + d // tmp2 = b * tmp1 // result = a + tmp2 var i_a, o_a = #mk; var i_b, o_b = #mk; var i_c, o_c = #mk; var i_d, o_d = #mk; var i_tmp1, o_tmp1 = #mk; var i_tmp2, o_tmp2 = #mk; var i_result, o_result = #mk; spawn_fthread { println$ read i_result; }; spawn_fthread { add (o_result, i_a, i_tmp2); }; spawn_fthread { mul (o_tmp2, i_b, i_tmp1); }; spawn_fthread { add (o_tmp1, i_c, i_d); }; var a = 1; var b = 2; var c = 3; var d = 4; write$ o_a, a; write$ o_b, b; write$ o_c, c; write$ o_d, d; var result = read i_result; println$ "Thread=" + result.str; println$ "Func=" + (a + b * (c + d)).str; //////////////////////////////////////////////////////////////////////////////////// It's important to note that when you do this: var x = read i1; var y = read i2; the write to these two channels MUST be in the same order as the reads or you get a deadlock or suicide. However this doesn't mean what you think it does!!!!! If these channels are written by two distinct fthreads, then the order is indeterminate, and the scheduler will conspire to make it work. If channel 2 is written first, the writer thread is just suspended, then channel 1 can be written. That thread is suspended as well. Now, we can read from the two channels in the given order. What this actually means is you can NOT expect this to work: write$ i2, v2; write$ i1, v1; This deadlocks (or suicides) because the reads and writes are synchronous, i.e. they're strictly ordered by control flow, but in the opposite orders. This cannot happen in a mathematical machine representing a tree, where each branch is a separate thread, because there is no ordering between fthreads: ordering is imposed by channels. So you can "fix" the above code by simply doing this: spawn_fthread { write$ i2, v2; }; spawn_fthread { write$ i1, v1; }; Assume these writes are done before the read. Now, I lied (AGAIN) when I said the scheduler would organise to do these threads in the read order. That's not what actually happens! When a thread writes to a channel, the THREAD IS PUT ON THE CHANNEL The scheduler forgets all about it!! It isn't on any inactive list. Well, I lied again. It is on an inactive list. The channel. That's what a channel is! Its a list of inactive threads. All of them waiting for a read. A channel is NOT something you send data down. Its actually a list of inactive threads. When you do the read, one of the threads supplies the read data, is popped off the list, and then rescheduled (the other wait their turn to write the data to some reader). A CHANNEL IS A SYNCHRONISATION VEHICLE The data transfer is a useful but irrelevant side effect. And in reverse: channels are also lists of threads waiting to read. Normally there's only one reader and one writer. It doesn't matter which one goes first, it gets suspended until the other one happens. Then the reader is resumed (to grab the data from the writer), and the writer is rescheduled. -- john skaller skal...@users.sourceforge.net http://felix-lang.org ------------------------------------------------------------------------------ Shape the Mobile Experience: Free Subscription Software experts and developers: Be at the forefront of tech innovation. Intel(R) Software Adrenaline delivers strategic insight and game-changing conversations that shape the rapidly evolving mobile landscape. Sign up now. http://pubads.g.doubleclick.net/gampad/clk?id=63431311&iu=/4140/ostg.clktrk _______________________________________________ Felix-language mailing list Felix-language@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/felix-language