Setting up ClojureCLR, calling it from a .Net console application and printing the results.
I’ve been working on a reasonably complex WPF application lately and threading issues have been getting me down. Clojure has been making a lot of claims about concurrency lately so I thought I’d give it a try.
”Clojure, being a practical language, allows state to change but provides mechanism to ensure that, when it does so, it remains consistent, while alleviating developers from having to avoid conflicts manually using locks etc.”
Clojure is built for the Java Virtual Machine but there is an ongoing effort to port it to .Net called ClojureCLR. I had some trouble finding any examples of how to use it so this post describes what I’ve figured out so far.
Building Clojure
First we need a working version of ClojureCLR. Since it’s still work in progress you need to build this yourself. The instructions in the wiki are pretty good if you read them carefully.
I didn’t read them carefully and had problems so here’s some extra notes…
When you download the DLR from CodePlex make sure you go to the source code tab and download the latest. I tried the latest packaged release which did not work.
When I cloned the source with git, I ended up with lots of modified files waiting to be checked in. To fix this I read the help from github about this and then did the opposite as I already had the setting on by default:
git config core.autocrlf false
If you set up your directory structure correctly you shouldn’t need to modify anything to get Clojure to compile. Mine looks like this
C
Development
clojure-clr
DLR_Main
This is the easiest way because otherwise you will need to mess with extern aliases on the references. I did not compile the Clojure.Tests project.
When the compilation instructions say “Do it” what they mean is open the ClojureCLR solution in Visual Studio and build it like a normal project. No scary build scripts to mess around with.
A Test Project
I added the projects for the Clojure and DLR dependencies directly to my example solution to make compilation and debugging nice and easy.
ClojureTest is my example console application. The scripts directory contains my example Clojure source which looks like this:
(ns test)
(defn add [a b]
(+ a b))
This defines a function called add in the namespace test. Can you guess what it does?
The clojure directory contains all the bits need to start and run a clojure environment. This is prepared by the Clojure.Compile project and is a copy of this folder:
clojure-clr\Clojure\Clojure.Compile\bin\Debug\clojure
Select all the files in both the scripts and clojure directories and set their build action to Copy if newer so they end up in your output directory.
Calling Clojure
We’re ready to go! Here’s my console application in C#:
static void Main()
{
RT.LoadScript(new FileInfo("scripts/test.clj"));
var add = RT.var("test", "add");
var result = add.invoke(3, 7);
Console.WriteLine(
"Clojure says 3 + 7 = {0}",
result);
}
First we locate our script and load it into the Clojure environment with RT.LoadScript. I have an imaginary cookie for anyone who can tell me what RT stands for…
We use RT.var to get a reference to the function we defined. The first parameter is the namespace and the second is the function name. Once we have the reference we use .invoke to call it in Clojure.
Wrapping Up
This is a lot of work to set up but that should get easier as the ClojureCLR project matures. In particular it needs a nice distribution with all the required Clojure files packaged into a .dll.
I was pleased that the final program is reasonably straight forward. It takes a few seconds to load the Clojure environment but once it is running seems to perform OK.
Now to try and do something useful with it…
22/01/2010 02:36 PM (UTC -08:00)
My blog is named after one of the most frustrating types of errors we get in programming, the generic one. This particularly nasty specimen is a common one from .Net:
Since I've seen a few Google searches head my way looking for a fix I thought I'd give a few tips. Here's the code that I used to generate this error:
static void Main()
{
Image image = Image.FromFile("Sample.jpg");
image.Save("ConsoleApplication1.exe");
}
Wow, that's a pretty cryptic error for 2 lines of code. The key is the filename passed in the second line, "ConsoleApplication1.exe", it's the name of the application we're running and of course you are not going to be able to save an image to it...
The most common cause of "A generic error occurred in GDI+" is that the application does not have permission to write to the filename you gave it.
In my experience of course. Here's some common things to check if you think this is your problem:
- Is the file in use.
- Does the user your application is running as have write permission to the file / folder.
- Are you running in a restricted environment (e.g. ASP.Net medium trust), and trying to write to somewhere you shouldn't (e.g. the Windows folder).
- Is there enough disk space.
Generic errors are especially nasty because not only do they present a problem with no hint of a solution, they also give you the impression that the original developer didn't know either. This case seems common enough that the developer should have been able to provide a better error message. In my opinion it's a serious twinkie denial condition for Microsoft.
If you've encountered any other interesting generic errors I've love to hear about them.
03/12/2008 10:49 PM (UTC -08:00)