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

Reply via email to