Update: All github ClojureCLR links have been updated to use the new repository at github.com/clojure/clojure-clr
After taking the summer off from blogging to spend time with the family, I am ready to get back to my blog. My first post of the ‘fall blogging season’ is a brief intro Clojure-clr. In this post I will walk you though getting clojure-clr installed, show you how to interact with the REPL and compile an application.
The Goal
By the end of this post I will be able to interact with .NET assemblies from the clojure-clr REPL and be able to compile a basic clojure-clr application from the command line.
The Setup
The first thing to do is to visit the Download Page of the Clojure-clr project on github. I chose to install the clojure-clr-1.3.0-Debug-4.0zip version. Once you have downloaded a version follow these instructions Getting started binary distribution page. Make sure to ‘Unblock’ the zip file before you unzip it. Failure to do so will cause exceptions to be thrown every time you try to run any of the executables or use any of the DLLs in the zip file. For ease of use I added the directory I extracted the files to into my PATH environment variable.
The REPL
Next, I started up cmd.exe and typed: clojure.main.exe . This will start up the REPL. If everything goes right you should see something similar to this image below.
The version number you see will be determined by the version you downloaded. Now that we have the REPL up and running lets take try some clojure code. At the prompt enter: (println “yep, it worked!”) and press the enter key. That should give you:
Ok, the ‘normal’ clojure seems to be working, now its time to try interacting with .NET.
Interacting with .NET
Now that we know we have the REPL working it is time to try out a few calls into the .NET world. The first call we will make is to Console.WriteLine. Since System.Console is loaded automatically by the REPL we can call it like this:
(System.Console/WriteLine “I just called a .NET method!”)
It works the same as the println call did. What if you want to interact with a .NET lib that hasn’t already been loaded into our namespace by the REPL? There are a couple of ways to do it one takes a lot of typing and the other takes about half the amount. To illustrate I will load the System.Windows.Forms assembly and load the MessageBox class. The verbose way to load a library is to call the Assembly.Load method:
(System.Reflection.Assembly/Load "System.Windows.Forms,
Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
When you hit enter after typing the above code in you should see this:
The second way to load a .NET assembly takes far less typing. It makes use of the Assembly/LoadWithPartialName method. Here’s what it looks like:
(System.Reflection.Assembly/LoadWithPartialName "System.Windows.Forms")
The results of this call will give you the same output as the more verbose Load call did. Either way you choose will work fine. If loading a particular version of a an assembly is crucial then I would go with the Load call. Otherwise I would stick with the LoadWithPartialName method.
Now that we have loaded System.Windows.Forms I’m going to include it into our namespace so I can use the MessageBox class so I can make calls into it a little cleaner. I can do that by typing the following in the REPL
(import (System.Windows.Forms MessageBox))
The call above tells the REPL we want to bring the System.Windows.Forms.MessageBox into our user namespace. This will allow us to use MessageBox/Show instead of System.Windows.Forms.MessageBox/Show. When entered the line of code below I saw the dialog box that follows it. Pretty straight forward.
(MessageBox/Show “Hi from clojure-clr!” “Clojure-CLR Dialog”)
Now that I’ve shown you how to make a call into .NET from the REPL let’s compile a clojure-clr ‘application’.
Compiling a Clojure-clr Application
For our example I will create an ‘application’ that consists of all the code that we entered into the REPL above in a file called intro.clj . After you have downloaded the file, change into the directory where it was saved. Then run:
clojure.compile intro
The compile command will create the following files in the same directory where the clojure.compile.exe file lives.
I haven’t found out how to tell the compiler where to put the output yet so for now I just run them from that directory. (If you know how to tell the compiler where to put the output please leave a comment below. I would really appreciate it!)
Running the intro.exe file will produce the println, Console.Writeln, and MessageBox.Show output just as it was in the REPL.
Summary
That’s it for my very brief intro into the world of clojure on the CLR. I walked you through using the REPL to call ‘normal’ clojure and how to interact with .NET. I also showed you how to compile a clojure-clr application on the command line.
In future clojure-clr posts I will convert my hugo project posts (Parsing Web Pages with Clojure and Enlive, Creating Hugo Awards DB-with Clojure, and Creating a Simple UI for the Hugo Awards DB) to hugo-clr using the .NET equivalents. Plus I plan on having a post or two on how to use the clojure-clr assemblies in a C# application.
Rob,
ReplyDeleteI'll follow your adventure with interest. Please contact me directly if I can be of assistance with problems that come up w/ ClojureCLR.
-David
David, glad to have you along. So far so good but I'm not doing any real heavy lifting yet.. I will take you on your offer when the need arises. Thank you for the port . It will help me get clojure into my work environment -Rob
ReplyDeletewould be nice see real examples clojure-.NET integration...maybe a simple gui or something interesting
ReplyDeleteAnonymous - I agree. In January I plan on writing a post that includes a .NET based UI that interacts with a DB. Thanks for the suggestion.
ReplyDeleteHey, I just wanted to let you know that your efforts explaining CLR / C# interop are much appreciated. I've been struggling with the most basic issues, like loading assemblies, and your website's been helpful. Would you mind if I added some of your tips to the Wiki pages on Github?
ReplyDeleteDaniel,
ReplyDeleteThank you for the kind words. Please feel free to spread the word!. What types of things are you using ClojureCLR for? I'm curious to see how others are using it.
Thanks,
Rob
Rob,
ReplyDeleteI'm only just getting started with it, really. I develop a lot of MVC apps at work and have been playing with Clojure at home off and on for a year or so, then recently I started thinking seriously about how it could be used for writing business rules and stuff like that, which can be tricky to code and enforce in vanilla C#. I'm still in the very beginning stages, though, like trying to get C#/Clojure interop working, getting Visual Studio to consistently recognize Clojure projects, etc. I'd like to contribute to the GitHub wiki and maybe even start a blog devoted to ClojureCLR, since there are very few resources out there for .NET devs interested in Clojure.
Daniel
Daniel,
ReplyDeleteSounds like our backgrounds are similar. Sounds like you've been playing with Clojure longer than I have. I'm currently using ClojureCLR at work to help us monitor our production environment. The clojure code base is making use of .NET DLLs for DB and RabbitMq interaction. I'm right there with, C# is nice but there are times I find myself saying 'this would be a lot easier/nicer in clojure.'
Let me know if I can be of any help along the way.
Rob
Will do. Thanks!
ReplyDeleteAwesome post! I was able to get the ClojureCLR REPL working from the wiki on the github page, but your post showed me what to do after I got it running.
ReplyDeleteHave you found good sources of documentation, beyond what is at github?
Thanks,
Rick
Rick,
DeleteThere isn't a lot out there on ClojureCLR at the moment. However, things are getting better. There are a couple of blogs you might want to check out. The first is http://clojureclr.blogspot.com/ . That is written by David Miller who maintains the ClojureCLR project. Another one to start watching is http://clrviaclojure.blogspot.com/ . In his blog, Daniel is sharing things he finds as he comes up to speed with ClojureCLR. He's just started blogging but I'm sure he'll have more content up soon. I've tried to put posts up on 'the basics', things you'll need in just about any thing you write with clojureclr. If there is a subject that you don't see on my blog let me know and I can help you out and/or write a blog post on the subject. I more posts queued up but at the moment with my day job and a few side things I have going I'm completely slammed.
Another place to check is stack overflow. There aren't a bunch of questions there but I have found the ones that are there helpful. I have also found that looking at the Clojure JVM how-tos will get you most of the way there too.
Also, I have a TOTALLY UNOFFICIAL version of CLR specific docs here: http://rippinrobr.github.com/gen_html_docs/ . PLEASE keep in mind these are pages that I've done on my own and may not TOTALLY reflect that truth. With that said, I use them and they seem ok.
Hope that helps. If you have any questions feel free to shoot me an email. Thanks for reading my blog!
-Rob
This blog post was helpful to get me past the ClojureCLR (1.4.0) REPL. Thanks!
ReplyDeleteSo, for experiment I include the ClojureCLR folder in the PATH. I put the source code intro.clj in a different folder. I was able to `clojure.compile` the source file intro.clj this way, but I could not run it. In order to run it, I had to put the ClojureCLR folder contents and the intro.* files together to run successfully.
Could you please point me to some resource, or describe how to run the compiled files without copying the ClojureCLR files into the same place?
I had the same effect even after setting CLOJURE_LOAD_PATH to the Clojure-CLR folder.
DeleteI was just about to tell you that I haven't been able to get that to work. What I did do is write a script for the app I wrote in my talk build.bat that copied everything over that I needed. It is not ideal but makes life easier. I wish there was a more elegant solution.
ReplyDeleteInterestingly, the command `clojure.main -m intro` works even when intro.* and CLOJURE_LOAD_PATH are in different folders. I guess this is because clojure.main loads all necessary components from its base directory.
Delete`clojure.main --help` lists a number of options that are useful. I wish `clojure.compile` supported a `--help` option too.