I've been MIA for awhile. I tend to go through high/low phases with my open source coding. A sure-fire trigger for a low phase is a "hard" problem for me.
The latest hard problem was how to implement continuations and inline functions into Sleep. This combination of features is necessary to really make the callcc construct useful. (FYI--I figured it out and both features are now implemented and checked into the subversion repository).
I've gotten a lot of mileage out of Sleep's yield command. Yield causes the current function state to be saved while simultaneously returning a value. This ability to save the current state of a function has been very useful to me. I was using this capability to support strong mobility of Sleep functions. http://www.jroller.com/sleepsnip/entry/mobile_agents_in_sleep
The problem is yielding an IP address was a cumbersome way to represent a go or move command. In my opinion the language shouldn't be clunky like that.
Enter callcc. callcc works like yield except it immediately passes control flow to a specified function. The specified function receives the saved state of the caller as a parameter. Interestingly enough, this specified function ends up owning the control flow for the caller and it can choose to return a value that will be returned to the caller of the caller. (confusing yet?)
The problem with callcc is it can be cumbersome to type callcc and some function over and over again. Just like having yield for my move abstraction was cumbersome. Enter inline functions. Sleep is not lisp or scheme. If it was, I'd support full on macros. Since its not I wanted to come up with a way to hide the details of callcc behind a function like entity. In Sleep an inline function call looks like a normal function call. Except inline functions execute inline within the current scope. Return, yield, callcc, etc.. within an inline function all affect the parent closure. So in a way, inline functions are like poor man's macros in Sleep.
I am excited as this will enable fun stuff like:
inline move{
callcc let({
local('$handle');
$handle = connect($host, 8888);
writeObject($handle, $1);
closef($handle);
}, $host => $1);
}
*pHEAR*. The middleware for this kind of asynchronous, mobile entity:
global('$server $agent');
while (1)
{
$server = listen(8888, 0);
$agent = readObject($server);
closef($server);
fork($agent);
}
It does not get much simpler than this. Oh, the mobile entity itself. Lets talk about a file copying mobile entity:
# assume $local_ip, $remote_ip are defined to two ip addresses running the middleware above
sub copyFile
{
local('$handle $data');
$handle = openf("database.dat");
$data = readb($handle, lof("database.dat"));
closef($handle);
$handle = $null;
move($remote_ip);
$handle = openf(">database.dat");
writeb($handle, $data);
closef($handle);
($handle, $data) = $null;
move($local_ip);
println("Success!");
}
As you can see callcc and inline functions will be quite a formidable combination. What type of flow control you want to abstract will be entirely up to your imagination. I'm excited for it. |