Stefan Rusek | First Post

First Post

Sunday, November 02, 2008

This is my first post on my new Blog. I am glad you're here and hope that you find something interesting.

I have been using an ASP.NET front-end to a WordPress installation for a while. The reason for the ASP.NET wrapper is that PHP sucks on windows, and ASP.NET has great caching tools. That solution was a pain and I don't care much for it. I really wanted a nice ASP.NET blog that worked just the way I needed. A couple weeks ago I discovered ASP.NET MVC and started playing around with it. It is awesome! I highly recommend that you consider it for your next web app. So I've been thinking of writing a new blog in MVC. Yes, I know the world is full of blogs, and I surely could have found one that worked the way I wanted. I had another motive. Benjamin Pollack and I recently started a side project to create a .NET port of Clojure. We call it Xronos. This is not an official announcement about it, but it does support MVC views. For this blog, the models and controllers are written in C#, and the views are written in Xronos.


Stefan Rusek | Strongly typed (def)s in Xronos

Strongly typed (def)s in Xronos

Sunday, November 16, 2008

Yesterday, I commited a changeset that greatly alters how (def)s and Vars are handled in Xronos. Previously, the Var class was modeled after the Clojure Var class. The Var class contained a root value of type object and for thread bindings it used a Box class (that basically wrapped a value of type object). The Var class provides the basic container for all global variables.

I was reading about Clojure's recent support for ahead of time compilation, and I noticed a few subtle differences between Var resolution in Clojure and in Xronos. Clojure resolves Vars at compile time and Xronos resolved them at runtime, so I decided to fix Xronos so it matched the behavior of Clojure. The change as simple enough and now the following code which would fail in Clojure also fails in Xronos:

(defmacro y [] x) 
(def x 5) 
(pr (+ 6 (y)))

This fails be cause y references the Var x before it is (def)ed, and in order to compile y we have to resolve the Var x.

As I was making this change, I realized that I now had access to the exact Var that was going to be used at runtime. This means that I have more options of what I can do with it as far as static compilation is concerned. So I broke Var into two classes VarBase and Var<T>. VarBase has the Name and Namespace properties and a few others, but Var<T> handles the value and a few other things. I also replaced Box with Box<T>. By default (def) will create a Var<object> which is functionally identical to the old Var class, but if you add metadata specifying the type then it will create a Var<T> of the specified type. This code will print 11 in both Xronos and Clojure:

(def #^{ :type System.Int32 } x 5) 
(pr (+ 6 x))

The difference is that in Xronos, the + is compiled to a integer add, while in Clojure, the + is forced to do dynamic addition. This example is not so great, since it tends to defeat the dynamic nature of the language, but in cases where the extra bit of performance is needed, then strongly typed Vars are great! There is also a very common case were it makes sense.

(defn add5 [x] (+ x 5)) 
(defmacro monkey [& expr] `(str "mon" ~@expr "key"))

Both of these result in a call to (def), and in Xronos it creates a Var<IFunction>. The advantage of this is that we now know at compile time that the Var<T> contains an IFunction. So (add5 6) now gets compiled to the eqivalent of:

varAdd5.get().Invoke((object)6);

instead of

((IFunction)varAdd5.get()).Invoke((object)6);

That simple change results in one less cast per form, and cuts startup time by about 30%. I thought about making def always infer and set the type of Vars, but the problem with that is that many types have compatible dynamic interfaces, and so no type makes sense but object.


Stefan Rusek | ASP.NET MVC Views in Xronos

ASP.NET MVC Views in Xronos

Tuesday, December 09, 2008

With the release of Xronos v0.1 comes an overhaul of how it works with ASP.NET MVC. First I removed the ASP-like syntax. The syntax was familiar, but it turns out that the syntax did not actually do anything helpful, because (pr) ends up making cleaner code. If that was the only change, then writing views in Xronos would be pretty lame. The new system is modeled after ASP.NET MasterPage system.

Enabling the ViewEngine is the first step toward using Xronos with ASP.NET MVC. Add a line to the Application_Start event in your Global.asax.cs file, before the call to RegisterRoutes(). The ViewEngine constructor takes any number of path names to files to compile immediately.

ViewEngines.Engines.Insert(0,
    new System.Xronos.Web.Mvc.ViewEngine("~/Views/Shared/Library.x");

Normal pages are simple to create, just write a (render) function that prints out your HTML:

(defn render [] (pr 
    "<html><head><title>" (get viewdata "Title")  "</title></head>" 
    "<body>Yay! it works</body></html>" 
))

This is fine and all, but most of the time you want a bunch of views that share a common layout. If you are familiar with how master pages work in ASP.NET, then Xronos master pages will be very familiar to you. In the master page file you need to have a (render) function and a params variable defined.

; ~/Views/Shared/Site.Master.x 
(def params) 

(defn header [] ... ) 
(defn footer [] ... ) 

(defn render [] 
    (header) 
    ((:body params)) 
    (footer) 
)

Then in your page you simply specify that you are using a master page and the content of the params.

; ~/Views/Home/Index.x 
(def master "~/Views/Shared/Site.Master.x") 
(xronos/refer 'mvc) 

(defn renderItems [] 
    (dorun (map blog/renderItem (get viewdata "Items"))) 
) 

(def content {:body renderItems})

Since Xronos compiles each file in its own namespace, each page is isolated from each other and cannot access any other functions unless your library puts them in an accessible namespace

; ~/Views/Shared/Library.x 
(in-ns 'blog) 
(xronos/refer 'mvc) 

(defn renderItem [item] ... )

At the moment Xronos only supports writing views. Sometime soon-ish, I hope to make it easy to write entire MVC apps in xronos. In the meantime, it is still an awesome language to write MVC views.