Advertisement

Customize
Dec. 9th, 2007 @ 02:47 pm (no subject)
About this Entry
me
I've been working hard on the Sleep 2.1 manual. My promise to the world has essentially been finish the code, redo the docs on the language, and then write a short primer on integration. Following those actions Sleep 2.1 will be completed.

One of the challenging aspects of writing this documentation is writing good examples. When writing this documentation I realize I'm not just capturing the syntax and basic use cases within the language. I'm also trying to capture the paradigms and ways of thinking in the language. This is important because it is the difference between an academic example and something people can use.

One example is fork. Fork is Sleep's abstraction for asynchronous computing. I say this because I don't want to call them threads. For the most part, Sleep's forks are completely isolated from each other. Of course they can share explicitly specified variables and then we get into locks and all that ugly mucky muck. But in any case I was trying to capture--how do I write an example of a multi-threaded tcp/ip client app? Something that users can cut and paste and begin using right away.

I learned Java in this cut and paste and begin using right away mentality. (Thanks Mr. David Flanagan for your Java Examples in a Nutshell Book--I'm quoting your name and book from memory, that shows what I really think of you).

Fortunately Sleep has had a strong ally in this type of development. I have a few coworkers and the incredibly, ah, vocal jIRCii user community who use Sleep. There feedback, endless support requests, and hunger for a solution have really driven the project. They have helped me identify holes in my functionality, real problems to solve, and of course what to document.

Case in point with fork. This weekend someone was trying to write a connection bouncer in Sleep. I think he actually is close to finishing it. He keeps adding a lot of stuff to it. But in any case he was trying to wrap his brain around fork and how to do computing in an asynchronous manner.

I managed an example that made it into the Sleep manual. If it weren't for him the technique I documented probably would not have been documented. Meaning ever user with a situation similar to his would be stuck trying to figure something out.

So I'm thankful for the users. They are really helping this come together.

The documentation is almost in a distributable state. So Sleep 2.1 should be coming soon. I will probably be ready to call it official in January 2008.
Nov. 26th, 2007 @ 02:23 am (no subject)
About this Entry
me
Sheesh, I am exhausted. I have to leave for Boston in 2 hours. Spent the whole night hacking code.

On the bright side I finally have a jIRCii website up. The hick.org crash wiped out the old site. For awhile I had nothing but a placeholder page up. Not really fair to jIRCii or to its user community.

On the even brighter side of things, I put out a jIRCii release today. I think I managed to fix some things that were really annoying folks. It took a little bit of persistent prodding for me to get the release out.

Ok, i'm gonna go pack and then hop on the road or something.
Nov. 12th, 2007 @ 11:32 pm (no subject)
About this Entry
me
During a google search for jIRCii, I found a link to the JavaPosse. A regular podcast on Java.

Anyways these guys were talking about IRC and jIRCii in particular. There was a little debate on how to pronounce it. They settled on jerky like beef jerky. Actually it is jay-eye-are-cee-two, a play on ircii the classic UNIX IRC client. It looks like I'll have to update the FAQ.
Oct. 18th, 2007 @ 01:19 am callcc and clever sleep hacks
About this Entry
me
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.
Jun. 15th, 2007 @ 07:21 pm (no subject)
About this Entry
me
Ok, this is a momentous occasion. I have only 4 open reports in the Sleep issue tracker right now. I've been down this low before but I plan to stay there this time, really really. :)

This next Sleep beta is going to be pretty good. Each beta usually focuses on one or two sets of features/areas to fix bugs in. This one focuses on adding support for Java class literals i.e. ^String to resolve in place to java.lang.String.class. This feature is useful for stuff like: if ($exception isa ^IOException) { ... } no more need for crazy [Class forName: "..."] calls throughout script code. The other advantage to this new literal is several functions in Sleep's library use a kludge where a string is specified and later turned into a Class. The &use function for loading a bridge into the current script environment is a good example of this. Life sucks for the scripters as they can't take advantage of any checking done by Sleep at compile time. Now this has been remedied.

For example, to use Andreas' JDBC bridge with this new enhancement:

import JDBCBridge from: "jdbc.jar";
use(^JDBCBridge);


This next beta also adds a bunch of nit picky features and fixes some nit picky bugs. I also spent some time and fixed the bugs I found in Sleep's try/catch mode. I've been doing a decent sized project and I've found using try/catch to handle all errors (debug mode 34) is really nice. However I've also found some corner cases that resulted in bugs with try/catch and I managed to fix those.

So that is what I've got going on in the Sleep world.
May. 18th, 2007 @ 08:33 pm Documentation Hacking
About this Entry
me
I'm happy, making some good progress on the Sleep 2.1 Manual. I've opted to treat the tutorial portion of the manual as a place to explain the constructs of the language and how things work overall. Explanations of abstractions and how to do certain things (like calculate the MD5 digest of a file) are left to the function reference.

This philosophical change has helped a lot. Now the manual is merely a reference and a quick start guide for scripters. This is leaving the door wide open for a real book on Sleep when there is enough interest in such a thing.

I wrote some scripts to help me out with the documentation. Namely my function reference pages are all generated from some simple text files. This keeps things consistent and greatly speeds up my ability to write pages. I'm one of those writers that tends to get caught up in how things are formatted. This was really slowing me down.

I still have two chapters to finish. I'm going to rewrite the chapter on interfacing with Java and the debugging chapter has to be done practically from scratch as well.

I now have pages for nearly all of the functions. About half of them are generated from my scripts, the other half have yet to be converted. Once these are done I have to start writing examples that show off how each function works.

I'm excited though. Writing new documentation is like writing new code. It is a slow process and it takes awhile before progress is visible. However as with code there is a point where so much is done that all work is just building on something that is already good. Doing development on something that is already good is a lot of fun. The Sleep documentation is almost at this point. Once the function files are all converted to my script system then I'll feel comfortable with where it is at.

Once the Sleep manual is done, I plan to go through the Sleep developers guide and try to distill and paste a lot of the good stuff from it into the Sleep javadoc. After that I will write a short pamphlet on integrating Sleep into an application. This process has changed considerably since the Sleep developers guide was written.

My aim is for the new developer's guide to be less than 10 pages total.

:)
Apr. 16th, 2007 @ 01:09 pm (no subject)
About this Entry
me
I hope no one is expecting anything from me for the next few days. I've been on a little bit of a traveling binge. This is definitely helping.

I find as a developer it helps to get away from my work from time to time. Namely when I get caught up in my work I start to get more and more ambitious. Each bug fix starts to require grander rewrites that supposedly introduce more elegance. Suddenly some far off idea becomes a must have feature. Really, my getting caught up in my work is dangerous to it. So a break is good.
Apr. 8th, 2007 @ 11:43 pm There is a madness to the method... resolution
About this Entry
me
There is a guy named Kurt who is an advocate of jIRCii. After I released b41 I quickly uploaded a small fix as I noticed a problem when running one of blue-elf's scripts with +trace enabled. Upon announcing this quick update he stated "this is why I use jIRCii whenever I want a GUI... you're #@&(&*($@&* ANAL!"

I've never thought of myself as an anal person. But I guess when it comes to code I may be. Tonight I've been working on how Sleep converts Scalars to arrays. Converting one dimensional types is easy, you resolve the best fit and convert it. With arrays there is the quirky question, how to convert the rest of the values and what to do if they don't convert, and how should the common denominator for the whole array be determined.

At the moment Sleep has array conversion code in place. It isn't bad but there are a few tweaks that can be made. Tonight is the first time I created an extensive series of test cases to cover this array conversion and it is revealing a few small problems (nothing cast() can't fix for scripters). But in any case, I don't want scripters to say "oh yeah, Sleep is horrible at converting arrays, if you decide to trust its array conversion... good luck". This may be the case but I'd like to do everything I can to at least make it work in a semi-logical and consistent manner.

Not going so well at the moment. I'll be happy so long as I fix a few things, avoid breaking backwards compatibility, and provide good error messages if necessary.

So that is whats happening on this side. I'll try to release 2.1-b15 tomorrow night.
Apr. 7th, 2007 @ 01:52 am (no subject)
About this Entry
me
Progress on Sleep 2.1-b15 is going well. I've managed to fix a lot of bugs and I took the time to search for some potential outstanding bugs as well. I've also added an assert command to the language as well.

So I'm down to one more bug fix before my list of open bugs is exhausted. That is a good place to be.

So now I'm trying to figure out the rest of the roadmap for Sleep 2.1. I have two features I'd like to implement (even though we're supposed to be feature complete right now), namely an optimizer and ||, && for use within expressions. The optimizer is more of an experiment I want to do. It doesn't have to make it into this version of Sleep but I'd like to be able to modify the Block/Step APIs to at least accept a visitor type object before Sleep 2.1 is out.

I may do the visitor thing this weekend and fixing my last bug. Beyond that I'll probably finish my Sleep bridge based on Dunamis (a java.net project, allows one to generate instances of classes with methods back by an invoke method). These things I'll release as part of Sleep 2.1-b15.

The &&, || thing I will try to do but unless it goes 100% smoothly, I'll probably defer it to a future development cycle. As for the optimizer same thing. I'll do an experiment to see how it goes trying to optimize a few things but I won't put that kind of heavy pressure on myself to finish an optimizer in such a short amount of time. Sleep 2.2 anyone?

Bare with me here, I'm merely thinking aloud and figuring out what comes next.

Of course all my release candidate versions of Sleep have to go into jIRCii for some good "field testing". Some of the bugs I just fixed were filed when jIRCii scripters came to me with questions about odd behaviors.

So ideally this weekend I'll make the compiled Sleep code traversable with a visitor object, fix my one last little bug, finish my dunamis bridge, and post a jIRCii update as well.

Tall order but definitely doable. Then of course I have to continue working on the Sleep 2.1 Manual. (: Sheesh, so much work to do yet.
Mar. 30th, 2007 @ 12:45 am Working with Dynamic Delegation
About this Entry
me
After spending hours writing that little Java 2D Sleep snippet, I was thinking to myself "self, there has to be a better way". Then I hit google and found other Java scripting lang devs had the clever idea long to implement subclassing by dynamically generating class files with the minimum amount of byte code to call back into their interpreter.

This idea appealed to me. The thought of embedding a 500kb byte code tweaking framework does not appeal to me, but whatever.

So the journey started with "Discover New Dimensions of Scripted Java", an article by David Weiss from 2003. http://www.javaworld.com/javaworld/jw-10-2003/jw-1003-beanshell.html

I decided I would investigate some of the byte code / classfile tweaking libraries out there and see what is what. First off, I have to ask, what is up with all of these fancy build processes people require now a days? Is it too much to ask to be able to download a .tgz file and type ant once the files are extracted? People want me to use maven or build extra ant utilities before I can compile their stuff. Really annoying. Also why can't folks generate one or two jar files, what is up with this multitude of functionality options?

Oh well, whatever.

So anyways I looked at Serp, Objectweb ASM, and BCEL. Objectweb ASM is the most appealing to me at the moment due to the fact the runtime for it is ~33KB. Size is important to me, especially if I am going to distribute their stuff with Sleep.

One really nice feature of BCEL and Objectweb ASM is the ability to load a Java class file against their tools and have Java code generated that shows how to generate the same class file with their libraries. I found this to be really useful.

With that said I eventually got kind of bored of it and decided to back off. Then I found Dunamis: https://dunamis.dev.java.net/

Dunamis is pretty cool. It works like the java.lang.reflect.Proxy class except it lets you specify a sort of invocation handler class with methods to trap and stop an invocation before it happens. If you allow it there are also methods for after and for when an exception is thrown. Kind of useful I suppose.

Whats more interesting seems to be the approach. You specify a Java object and it creates a class file implementing the same methods/interfaces of this class file except the body of each is set to go to the invoker interface first and foremost. A reference to the original object is kept on hand for calling into its methods if need be.

Not a bad approach and not too complicated.

I'm working on a Sleep bridge right now based on dunamis. I plan to play with it and release it on the Sleep homepage. If it turns out to be a technology I (or others) can't live without, then I may consider writing this type of functionality with ObjectWeb ASM and including it in Sleep's core. Dunamis uses BCEL and the two together create a runtime that is ~500KB. Not really going to fly for inclusion into the core Sleep library.

In the meantime, if you're curious as to what I'm planning to do, it is *really* simple:

$component = [new java.awt.Component];
$delegate = delegate($component);
intercept($delegate, "paint", { ... some closure to handle painting ops here ... });

Thats pretty much it. I plan to have access to the original delegated object through $super (maybe $self would be more appropriate). So one could do [$super paint: $1]; if they so desired.

I'd have to look at how well abstract classes and such are handled but I don't think it'll be a problem.

So anyways that is something I'm looking at right now.
Mar. 28th, 2007 @ 12:24 am (no subject)
About this Entry
me
I posted a new blog entry to the Sleep snippets weblog. Marty has been asking about how to draw to a Canvas from a Sleep script so I figured I would get him hooked up. I had no idea it would take me over 4 hours to flesh out the code, clean it up, and write the blog entry. Should be worth it though, I was able to get some good information into the entry about threading in Sleep and protection resources. Not to mention it shows off how to access Java from Sleep as well.

http://www.jroller.com/page/sleepsnip?entry=scripting_java2d_within_sleep

Here are some of the entries I'm currently thinking about writing. If you have any suggestions for some Sleep snippets you'd like to see, please let me know.


  • GUI Automation through Java's Robot API using Sleep

  • Dynamically loading 3rd party Jars with Sleep

  • Implementing polling style I/O in Sleep

  • Coroutines and Sleep

  • Logic Programming in Sleep (ala yield prolog project)

  • Why functional programming is cool--build a website in Sleep

  • Sleep Continuations Based Webserver--why not?



That is what is on tap for now. Anyways I'm off to bed. Night.
Mar. 20th, 2007 @ 10:44 pm (no subject)
About this Entry
me
Sheesh, it looks like I have what will be Sleep 2.1-b14 ready to go. I'll release it on Sunday. Hopefully no one is expecting anything earth shattering. The release merely fixes a few small things, normalizes index parameters in array functions, and this release adds a splice function.

I still have a few open things left in the Sleep issue tracker. One of them is ensuring line numbers don't get skewed on Windows (I don't believe this is happening) and ensuring there isn't a Unicode stepping on my face problem with using Java Strings to store byte arrays.

Other than those small things, I think Sleep 2.1 is pretty much feature complete. If I have time I'll integrate this beta into jIRCii and try to do a simultaneous jIRCii/Sleep 2.1-b14 release. While scripters are pounding on the latest Sleep I'll spend my time updating the documentation and seeing where that gets me.

Hopefully the scripters will be happy. I've logged over 85 Sleep 2.1 changes since the last jIRCii beta. There will be a lot of new stuff for them to play with. Also, again if I have time, I might try running a few jIRCii scripts to see how well backwards compatibility fared.

We're getting there. Sleep 2.1 is looking good. Now I have to figure out how to publicize it. Speaking of which April 6 will mark 5 years since Sleep's birth. http://sleepjava.sourceforge.net/ Don't get too excited. I originally had no anticipation of turning Sleep into anything real.

In 2002 it was a toy I was playing with. 2003-2004 my goal with Sleep was something that I could integrate into jIRCii. 2005 in a relatively short development cycle (5 months) I developed Sleep 2.0. I was motivated to make Sleep 2.0 contain some key features (closures and access to Java classes) due to a blog comment someone made on Sleep. They said something like: "it doesn't have closures, no objects, not impressed". Ah well.

Sleep 2.1 has been in development since maybe May 2006. My goal with Sleep 2.1 is to fill the holes in the language and clear out some of the show stopper issues folks encountered using Sleep to do "real" stuff. The time between now and the release of Sleep 2.0 has really allowed me to capture a lot of feedback and get a handle on what the language needs to move forward.

Anyways, I'm excited about the release. Should be interesting to see what happens from here.
Mar. 15th, 2007 @ 11:51 pm (no subject)
About this Entry
me
So I am currently working on implementing the try/catch stuff into the sleep interpreter. I've got the basic mechanism in place, including saving handlers as appropriate within coroutines. Now, before I can finish my implementation I have a few decisions to make.

I should probably note exceptions will only be generated when java throws one via a HOES call or when a scripter chooses to throw one using the throw keyword. All other errors will remain the property of checkError().

1. What should Sleep do if an exception goes unhandled?

There are multiple possibilities here. I could simply make the interpreter check for an exception handler right away and then if there is none have it do the default behavior of flagging a value for checkError(). This is tempting as it would prevent any breakage of backwards compatibility. However this would also create really bad semantics for exceptions i.e. without a handler the step fails and a message is generated where as with a handler whole frames are skipped until the handler is reached. This could be especially ugly if a script encloses some code in a try/catch block, calls a function, and the producer of the function didn't expect a try/catch block to be utilized.

So assuming I choose to make the exception just bubble up, I'm thinking of having the top most level deal with the exception by firing a warning message saying the exception wasn't dealt with and so the script exited.

The other option is to swallow the message and do nothing. Something I don't plan on doing.

Another crazy option is to make Sleep exceptions work totally unlike java exceptions i.e.:

try
{
$x = [Integer parseInt: "sjdfjasfj"];
}
catch $ex
{
println("Yeap, we failed to parse the integer... :( - $ex");
return $null;
}

Given that scenario above, I could make the handler get called as a function and use its return value as the value of the failed call. Without a handler in place Sleep could just do the default error flagging behavior.

----

What will I do? most likely: I will probably make an uncaught exception print a warning out to the runtime warning watchers. I will keep behavior pretty much inline with what Java does now. I don't really like this option as much because scripters who don't know about exceptions will be forced to learn (right now exceptions are presented through the checkError mechanism).

I will also consider adding a debug option to turn any checkError type stuff into exception messages. Maybe.

Still need to figure out what stack traces will look like as well.

Big PITA!@#$%^ :)
Mar. 12th, 2007 @ 08:08 pm Adding exception handling to Sleep
About this Entry
me
I love programming. Have I ever mentioned that? If not, its probably time I mention it now. I just love the mental exercise of it. That is actually part of my motivation hacking on Sleep. I love taking a feature idea and trying to figure out how to make it fit into Sleep in a cool way.

Right now I'm sitting in a coffee shop trying to figure out how exception handling will fit into Sleep. Once Sleep can handle and throw exceptions I will feel it is pretty good to go as far as being feature complete.

So I've been brainstorming a bunch of ideas for this one for awhile. Here is my current plan.

I plan to add new syntax to the Sleep language to allow try catch blocks. Nothing too fancy, this is a scripting language after all:

try
{
# some code to try...
}
catch $error
{
# uh oh something broke... $error is the thrown object whether
# it descends from Throwable or it is something else
printAll(getStackTrace()); # prints a stack trace from the sleep interpreter
}


So that is the syntax. What will this compile too? You'll like this, maybe.

Basically I plan to add a new atomic step (aka instruction) to the sleep interpreter. Believe it or not, I plan to call it Try. This Try atomic step will store the variable name specified after catch, the block of code to try to execute, and the catch block of code.

Upon execution the Try block will install the catch block into the current script context (script environment specific and theoretically thread safe) and it will also set the try block as the current handler owner.

It will then invoke the try block within the current script context. Nothing too special here.

The try block can then go on doing its normal thing. If there is an exception worth knowing about here is what Sleep will do:

1. the atomic step will flag that an exception has occured, this will use the same mechanism used for return, yield, and other things that "return stuff"
2. at the block level, the block will check for an exception return case. If we are experiencing such a case then the block will add the current execution information to the stack trace. It will then check if a handler is installed or not.
3. If a handler is not installed it will go the old route of firing a runtime warning and then clearing the exception.
4. If a handler is installed, the block will check if it is the owning block, if it is not, the exception will be allowed to bubble up (remember the highest level block with a try is the owning block).
5. If the handler is the owning block, it will execute the handler, and clear the return code.

Thats pretty much it.

I still have to figure out how I am going to let an exception escape the sleep interpreter when a pseudo object is executing. Also the stack trace building needs some fuzzing out. Finally the last things I need to double check is that coroutines won't break this scheme.

We'll see. Still some ways to go but I think I am close to having what I want. We'll see. :)
Mar. 11th, 2007 @ 09:48 pm What is going on...
About this Entry
me
Two weeks ago I received word on my two conference submissions for Sleep. Both of them were passed over in favor of other submissions. This wasn't totally unexpected. My abstracts could certainly have used some work. And I am aware that Sleep is kind of a sleeping (no pun intended) project.

So, you may ask... why do I continue with it? The answer is pretty simple. Because its fun. :) Actually I do eat my own dog food and there are a few people around me (in real life and on IRC) who use Sleep as well. The language really does have a lot of what I like about Perl. It is an ugly hack but man, you can DO THINGS with it.

So there is a small cadre of us using Sleep. As folks make me aware of roadblocks I file reports into the BiTCH system.

As these roadblocks become fewer and fewer I get more and more excited about the project. Maybe once we're feature complete I'll start writing some articles and put some effort into getting the word out. :) Maybe.
Feb. 12th, 2007 @ 09:12 pm (no subject)
About this Entry
me
I'm back. I'm working on getting my head around some code I left off with about 2 months ago. Hopefully there will be a new beta within the next few weeks.
Dec. 18th, 2006 @ 09:24 pm (no subject)
About this Entry
me
Its been awhile since I've updated. I'm struggling with a little bit of burnout. Which is a shame because my todo list is so small right now. Hopefully after the holidays are over I'll be moving Sleep forward some more.

I've had a real desire to write lately.

In case anyone likes the snippets, I wrote a sleep snippet to chop the first 5 seconds out of a bunch of mp3s that were infected with an obnoxious reminder of where the file came from. You can check it out at: http://www.jroller.com/page/sleepsnip?entry=get_to_the_good_stuff

In other news, I'm still planning to submit the Jazoon Abstract. I submitted a JavaOne abstract/outline last week. So I've at least started thinking about how I want to approach things.

That is all the news for now.
Dec. 6th, 2006 @ 01:16 am One night in #jIRCii
About this Entry
me
Most of you probably know the main project using Sleep is jIRCii. jIRCii is an internet relay chat client with a pretty healthy user community. Tonight in #jIRCii on EFNet, one user was soliciting some help on fixing his /scan alias. blue-elf (a major voice in jIRCii/Sleep) was basically throwing back one-liners to help out the situation:



Amazing what one can do with a line of code. Back when there was a very closed beta community for jIRCii, I toyed with the idea of integrating Sleep into the client. I distributed a doc describing this integration with one of my betas and one of the users sent me a script for an integration that didn't even exist yet. I thought that was pretty satisfying. Seeing people toss around crazy Sleep expressions though is still pretty satisfying. Part of what keeps me motivated working on the language and improving it.

In case you want to understand the code blue-elf pasted (click the screenshot to see the conversation):

/eval echoColumns(getActiveWindow(), join("\t",map(lambda({ $mode = getModeFor($1, $chan); $var = iff($mode, $mode, " ") . "\c15" . left($1, 10); return "\c14[\c12$var" . " " x (10 - strlen(strip($var))) . "\c14]"; }, $chan => getActiveWindow()), getUsers(getActiveWindow()))), 0.8)

/eval is a command to take whatever expression you give it and evaluate it using Sleep. The above basically prints out a nicely formatted and columnized list of users in the channel. Here is what the code looks like with some better white space:

echoColumns(getActiveWindow(), 
            join("\t", map(lambda({ 
                              $mode = getModeFor($1, $chan); 
                              $var = iff($mode, $mode, " ") . "\c15" . left($1, 10); 
                              return "\c14[\c12$var" . " " x (10 - strlen(strip($var))) . "\c14]"; 
                           }, $chan => getActiveWindow()), 
                  getUsers(getActiveWindow()))), 0.8)


In case you're curious as to what all this really means. echoColumns takes 3 parameters. A window to echo too, a tab separated string of "columns" to display, and a percentage of the screen that these columns should fill. As the window is resized the columns are wrapped to fit to the display with that percentage (80% in the case above).

So getActiveWindow is obviously the window. What elf is doing is mapping an anonymous function onto an array of users on the channel. he uses lambda to create a new closure with $chan installed into the this scope of the closure. map is used that closure onto the results of getUsers(getActiveWindow()) and the join function is used to join all of the return values of map into a single string with each value separated by the tab character.

Nice one liner.
Dec. 3rd, 2006 @ 01:38 am The Evil Coroutine Bug Strikes again...
About this Entry
me
So awhile back I documented my experience implementing recursive coroutines into Sleep 2.1. Looking back I didn't quite cover the full saga so I'll catch you up real quick.

I was reading over the python PEPs and I was really impressed by what recursive coroutines could do. Just the nice simple power of them. And I knew I wanted this in Sleep. I implemented basic generators without to much trouble. When I started allowing coroutines to call themselves I built a simple example based on the Python PEP 255. An example that basically did a preorder, inorder, and postorder traversal of a tree data structure. Just to fill in space I'll paste it here now:

# do a preorder traversal of a tree closure
sub preorder
{
   local('$x');

   if ($1 !is $null)
   {
      while $x (preorder([$1 left]))
      {
         yield $x;
      }

      while $x (preorder([$1 right]))
      {
         yield $x;
      } 

      yield [$1 label];
   }

   return $null;
}

sub tree
{
   this('$label $left $right');

   if ($0 eq "left")
   {
      return $left;
   }

   if ($0 eq "right")
   {
      return $right;
   }

   if ($0 eq "label")
   {
      return $label;
   }
}

sub node
{
   return lambda(&tree, $label => $1, $left => $2, $right => $3);
} 

$root = node("root", node("+", node(3), node(4)), node("*", node("-", node(6), node(2)), node(30)));

println("Pre order tree traversal");

while $traversal (preorder($root))
{
   println($traversal);
}


I think dissecting this code would make a perfect Sleep snippets blog post. I'll add that to my todo list. Anyways I think it was the preorder function that kept going into an infinite loop on me. I had no idea why and trying to track down the bug was incredibly frustrating.

Finally I put in some println statements into the code and everything worked without a problem. I was quite confused. And then I noticed when I put a println statement into the code following the third yield statement it worked. Anywhere else, it didn't. I was really confused. Finally I broke down and I added a null op instruction to the sleep interpreter. This instruction was added after every yield request. A hacky fix, I didn't understand why it fixed the problem, but it did.

So here we are several Sleep betas later. Marty, one of the guys I work with, was looking for some code to generate a decent listing of two directories and compare them. I read somewhere that comparing two trees with a good coroutine implementation is absolute cake. Doing so without coroutines sucks. So I proceeded to try to write a function to act as a directory iterator.

sub traverse
{
   local('$f $temp');

   foreach $f (ls($1))
   {
      yield $f;

      if (-isDir $f)
      {
         while $temp (traverse($f))
         {
            yield $temp;
         }
      }
   }
}

while $blah (traverse("/Users/raffi/sleepdev/"))
{
   println($blah);
}


Unfortunately the traverse function would work for a few iterations and then eventually it would completely crap out. Again I had no idea why. I just started tackling this problem today. I was shaking in my boots at the thought of going through another 3 week hunt-for-the-bug-in-the-coroutine-implementation binge.

Then I figured it out. I have no idea why my null op fix made so many situations work, but here was the real problem.

When a yield is requested, Sleep knows it needs to save up all of the past context. This is done by setting a flag (same mechanism as return) that forces all of the blocks to immediately exit all the way up to the top level caller. Note: reseting this flag is very important, this is why you always use SleepUtils.runCode to call Sleep code. Not reseting this flag was a cause of many early and hard to find bugs back in the day. Anyways... when a yield is requested Sleep knows to start saving each block and "program counter" value to what I call a context stack.

When a coroutine is resumed, Sleep starts iterating through the bottom of the saved context stack. It just grabs the block and the program counter value and starts ticking away again. Once that block is exited the next block in the context stack is executed, so on and so forth until all the blocks are exhausted. Without coroutines this happens thanks to Java's call stack. When a block exits, the evaluate function for that block returns and the calling block picks up executing where it left off. Nothing special.

Now another detail. When a coroutine is resumed, a new context stack is made and the old one is iterated through as mentioned above. The idea here is that if a yield happens then the new context stack won't screw up the old one i.e. they won't conflict with eachother. Especially important when we're doing recursive coroutines (i.e. the same function calling itself, resuming itself, saving itself, etc..).

Now here is a fun question. What happens when we're evaluating the current context stack and a yield is requested. Well of course all that bubbling up and saving happens, right? This is fine. This captures the stuff from the Java call stack quite well but not the stuff from the resumed call stack.

Without explicitly dealing with this situation, the old code was basically continuing to evaluate the old context steps which would cause an instruction to be advanced in the old saved stuff and thanks to the flow_control_yield flag the program counter and block would be saved. This is why the null op fixed some of these problems. So long as the simulated stack wasn't too deep all that would get skipped was the null op.

I added some code to the sleep interpreter to check for the yield flag within the evaluate old context function. If a yield is requested then the remaining current context is immediately dumped to the new context that is being saved.

Once I did that everything worked. I was also able to eliminate the null op following the yield step.

Good news.

Ok, now I'm going to crash. I've done enough coding and debugging for one day.
Nov. 30th, 2006 @ 09:24 pm Added a profiler to Sleep
About this Entry
me
Today we get to play a game of good news, bad news.

As you may remember from past posts I am currently hacking this sleep based web app server/application at work. It goes live next week. I am really happy with the number of bells and whistles in the app in this short amount of time i.e. consistent tables on every page that can be sorted by any column. Granted most frameworks provide this kind of stuff, but i was able to build what I needed to do it rather quick. In any case that is not what I am here to write about. My hack of a web server has many limitations, I'm just surprised that I am having fun writing a server side web thing again.

However that is not what I am here to write about today. I am here to write about how hungry I am right now. Actually, I'm not interested in writing about that, but I am dreaming of the moment when I will get up and go make myself a sandwich.

The performance in this little web app on my Macbook Pro has been pretty good. As I render more and more rows on a page, of course it takes a little longer to generate that, but no complaints. I then opted to run this stuff on someones Powermac G5 (not a slow machine by any stretch of the imagination) but performance was about 3x slower than on my Macbook Pro (wow, Apple's marketing must have been right about the new intel macs). So I figured it was time to look at optimizing.

Of course you can't do optimization without profiling. So I added a profiler to Sleep. Nothing fancy. If you have a tracing debug mode, Sleep will start collecting statistics for each function i.e. number of calls and how much total time has been spent in that function.

So the good news is Sleep has a profiler. I put it in on a trial basis thinking, if it helps me optimize my web app, I'll keep it.

The bad news is, I haven't really found anything I could optimize. I have a printTable function that is taking all the time. Every other function is being called many hundreds (and some thousands!!!!) of times. I'm going to look at printTable but I don't expect I'll be able to get it down too much. We'll see. Maybe I can.

On the flip side, I didn't know how this profiler would turn out. But it actually has been kind of fun looking at what my code is really doing. So even though it didn't provide a blindingly obvious place to start optimizing, it has added to the fun factor. So I think the feature is going to stay. I never imagined Sleep would have a built in profiler.