Clojure CLR/.Net on Windows
My latest work requires me to get more intimate with development on the Windows platform again, and I'm taking this opportunity to explore Windows CLR and .Net using Clojure, or more correctly Clojure-CLR, the version of Clojure that is hosted on the .Net platform. Unfortunately, there is a lot less documentation about Clojure-CLR, so it probably is a bit harder to get started.
Downloading and building clojure-clr
You can get clojure-clr from https://github.com/richhickey/clojure-clr , where you can either download it as a pre-compiled binary, or download/checkout the source and build it yourself. If you want to build it yourself, make sure you download the lib.zip file as well; it contains the library dependencies you need for building from source (in addition to the .Net 3.5 or 4.0 SDK).
To build clojure-clr, open the Visual Studio "solution" file Clojure/ClojureCLR.sln . After successful building, you will find the binaries inside bin/4.0/Release (or 3.5 if you build against dotNet 3.5, and/or Debug instead of Release if you build a debug release). After building, you can fire up Clojure.Main.exe to have the famous REPL (http://en.wikipedia.org/wiki/REPL) up and running.
Running clojure-clr
Windows isn't well known for it's rich selection of command line shells, probably simply because they aren't used all that much. Doing simple scripting and programming in REPL style environments requires some method of entering commands and getting output, and the command line shells are usually the most "universal" method of doing this. Windows offers the default cmd.exe for all users. The Windows Powershell is also available, but possibly not installed by default. Both of these offer limited choices (if any) as far as resizing goes, including both window size and font selections and sizes. And the default font selections in Windows are usually too large and almost always in bold.
Having been somewhat spoiled from the relatively rich selection of choices in the Linux environment, I installed Cygwin (Unix toolset for Windows - http://cygwin.com/) and had a rich shell available (I selected mintty), which allows for full and easy resizing of windows and font sizes. Unfortunately, due to the way Windows console applications work by default on Windows, there was an issue with arrow keys and command line editing inside the Clojure REPL. In a REPL you need command line editing and history to work.
It seems the author of mintty has created a fix which works great with Clojure on Windows, see http://groups.google.com/group/mintty-discuss/browse_thread/thread/1f9cf... . If you start Clojure inside conin ("C:\>conin Clojure.Main.exe"), command line works great, and you get a rich command REPL environment for developing using clojure-clr.
Clojure Hello World in Windows
Microsoft has been in catch-up mode for the last decade, and unfortunately their API/development platforms shows. If you want to implement a "native" Windows GUI application today, the choices for the .Net/CLR platform is either Windows Forms (Forms) of the Windows Presentation Framework (WPF). While a lot can be said for either framework, the usual recommendation is to use WPF. I've managed to put together examples of two simple hello world style examples below for both frameworks. The first one, using Windows Forms, is pretty straightforward.
(import '(System.Reflection Assembly)) (Assembly/LoadWithPartialName "System.Windows.Forms") (ns helloworld (:import (System.Windows.Forms MessageBox))) (MessageBox/Show "Hello world")
The second hello world example is a bit more complex. It starts a Windows application, opens an empty main windows and changes the title in the window to "Hello world". As the code demonstrates, it is not as straightforward, partly because it does more (starts the GUI app in it's own separate thread), and partly because WPF requires a larger footprint to get a minimum application up and running.
(import '(System.Reflection Assembly)) (Assembly/LoadWithPartialName "PresentationFramework") (Assembly/LoadWithPartialName "PresentationCore") (Assembly/LoadWithPartialName "WindowsBase") (ns hellowpf.core (:import (System.Windows Application Window)) (:import (System.Windows.Threading Dispatcher DispatcherPriority)) (:import (System.Threading ApartmentState ThreadStart Thread))) (defn gui-main [] (let [app (Application.) mainwin (Window.)] (.set_Title mainwin "Hello world") (.Run app mainwin))) (defn wpf-eval [uithread repl-ns-sym data] (.Invoke (Dispatcher/FromThread uithread) DispatcherPriority/Normal (gen-delegate Action [] (clojure.main/with-bindings (in-ns repl-ns-sym) (eval data))))) (let [threaddelegate (gen-delegate ThreadStart [] (gui-main)) uithread (doto (Thread. threaddelegate) (.SetApartmentState ApartmentState/STA) (.Start))] (clojure.main/repl :eval (partial wpf-eval uithread 'hellowpf.core)))
While the Forms example can be run repeatedly from within the Clojure REPL environment, the WPF application can not. It seems related to the fact that the System.Windows.Application instance can only be used and instantiated once within an interactive environment such as the REPL. While this may not be a big problem for running the app as a "standalone app", it certainly does not make it very practical to work with such applications from the REPL environment, unless you do not mind restarting the Clojure REPL every time. According to answers I've found through Google, the Forms API seems to offer simple support for restarting an application within a process, it seems the same functionality is lacking for WPF applications. It may very well be that it is and should be possibly, but based on my finding it's not very easy. If somebody wants to clue me in on how I can restart a WPF application without restarting the process, feel free to write a comment.
Add new comment