Originally published on: Fri, 14 Aug 2009 02:38:36 +0000
Like a fair number of other developers, I am trying to acclimate myself to programming in one or more dialects of Lisp. I've recently begun to toy with Clojure, a modern Lisp that runs on the Java Virtual Machine.
Before really engaging in some sort of all-out project in Clojure, I thought that I could ease my way into the language by attempting to use it as an embedded scripting language for a simple Java application. I looked through some of the online documentation on Java/Clojure interoperability. The task didn't seem to be too much to attempt in a short amount of time.
I decided to first create a small Java program that performs a simple task in a controlled loop. This program took shape as a small screen-capture utility.
ScrCapture.java
The above program iterates ten times, incrementing a counter from zero to nine inclusively. The entire screen dimensions are retrieved. Then, the entire screen is captured into a file with the iteration number in the file. A beeping sound is generated followed by a ten second delay before iterating through the loop again.
If you execute the above program, you should see the following output: java ScrCapture Captured as capture_0.jpg Captured as capture_1.jpg Captured as capture_2.jpg Captured as capture_3.jpg Captured as capture_4.jpg Captured as capture_5.jpg Captured as capture_6.jpg Captured as capture_7.jpg Captured as capture_8.jpg Captured as capture_9.jpg I wanted to move all of the different elements of the above ... the number of iterations, the sound, the delay, the image filename, the image dimensions ... into an external Clojure script.
The resulting Java program is as follows:
ScreenScript.java
One of the first things I'd like to note is that I included a package definition in ScreenScript.java. I didn't have a formal package name for ScrCapture.java and all worked well. I ran into some issues in Clojure with the . special form.
I tried to use the . special form to invoke static methods I'd provided in the ScreenScript class from the Clojure script. An example would be this call to the sleep method I provided:
(. com.mailsend_online.ScreenScript sleep 2000 )
Until I placed the ScreenScript class in a formal package, Clojure had real issues finding the class. I tried various classpath changes to no avail.
Onward...
One goal in writing ScreenScript was to provide a series of static methods available for use by the Clojure script. I provided the methods screenWidth(), screenHeight(),captureRectangle,sleep(),and beep(). The Clojure script would mimic the main loop from the ScrCapture.java.
Although I had intended to create a loop in Clojure to perform all of the screen capture operations, I found that I really need practice with Clojure's flow-control facilities. This is one of the areas of Lisp where I hope to grasp the beauty of recursion to control iterations. I made a few small attempts to no avail, so I ended up keeping a for-loop in the ScreenScript program.
To compile the above program, make sure that clojure-1.0.0.jar is in your classpath.
ScreenScript first loads the Clojure script specified on the command-line. The method RT.loadResourceScript() loads the specified script and also initializes the Clojure runtime environment.
After the script is loaded, two Var objects are initialized ( captureLoop and maxIterations ) so that I can invoke their like-named functions in the specified Clojure script.
The code invokes maxIterations first to determine the number of times to loop. This is one area of the code that I'd like to change so that it will, in a future incarnation, leverage Clojure's flow-control.
In the loop body, the Clojure method capture-loop is invoked.
Please consider the following Clojure script that is used in conjunction with ScreenScript:
cap.clj
The call to max-iterations in the above script yields a value of ten. I don't yet know how to simply make a symbol that I can read, so I left this mechanism in the form of a function.
The capture-loop function accepts on parameter named i. The calling Java program passes in the iteration number ( relative to zero ). The capture-loop function uses i to form up the name of the output file.
Note that in the Clojure script above, we only capture a 400 by 200 pixel section of the screen, we use a different file naming convention option for shorter names, we only delay 2 seconds between each iteration, and we output a different message that does not contain the generated filename.
The output from the above might look like this:
java com.mailsend_online.ScreenScript cap.clj Capture number 0 Capture number 1 Capture number 2 Capture number 3 Capture number 4 Capture number 5 Capture number 6 Capture number 7 Capture number 8 Capture number 9
If we wanted to completely replicate the functionality of ScrCapture.java, we could make calls to screenWidth and screenHeight so that we capture all of the screen and could change all of the Clojure code to parallel the parameters used in the original program.
The primary goals I had were to learn how to call a Clojure function from within Java and also to learn how to call a Java method from within Clojure. The resulting Clojure host isn't quite perfect yet, but I'll be exercising Java/Clojure interoperability again in the near future.
Unless otherwise noted, all code and text entries are Copyright ©2009 by James K. Lawless
Views expressed in this blog are those of the author and do not necessary reflect those of the author's employer. Views expressed in the comments are those of the responding individual.

Save to StumbleUpon
Digg it
Save to Reddit
Share on Facebook
Share on Twitter
More bookmarks
Click **here**
A JavaScript REPL for Android Devices
A Review of Kevin Mitnick's Book Ghost in the Wires
Play MP3 Files with Python on Windows
Send GMail From the Windows Command-Line with MailWrench
An Interview with Brad Templeton
A JavaScript REPL for Android Devices
Thwarting HTTP Referer Trackbacks
Mad Schemes : Learning Lisp via SICP
Why Some Web Sites will go Dark on Jan 18th
Book Review : Paull Allen - Idea Man
A 90's Experiment in Online Systems - The U.S. West CommunityLink Service