Friday, September 20, 2013

A taste of Spanner

Spanner is the name of my soon-to-be-released open source statically typed domain specific language for building Knockout web applications in C#. Here is a very brief sample, which I will let stand by itself: Build and run this program and you get the following web page:
+ = which is .

Now, this is a fairly trivial example, but it illustrates some of the key points about Spanner.
  • A Spanner program is completely, strongly, statically typed -- it's just C#. As soon as you make a type error in your program, Visual Studio will list the problem areas in the error window. The generated JavaScript code cannot contain type errors (well, up to the point where you start including third-party JavaScript libraries). This alone makes Spanner valuable.
  • Strong typing means you get strong refactoring support from Visual Studio.
  • You don't need special syntax for expressions: you can freely use +, -, /, *, etc.
  • Because you are writing in C#, you have all the usual mechanisms for abstraction (i.e., functions!). You are not limited to the ad hoc hodge podge of compromises necessary in ordinary HTML + JavaScript development.
  • You don't need special syntax for Knockout observables -- Spanner knows which variables are observables and which are plain old JavaScript variables and generates the appropriate code for reading and writing them. Indeed, observables are much more transparent in Spanner than they are in JavaScript.
  • All the documented, well-typed parts of Knockout are supported.
  • Every HTML element and every well-typed JavaScript construct is represented by a correspondingly named Spanner function.
  • The correspondence between HTML attributes and view model variables is transparent -- you never need to embed code or identifiers in HTML strings. This is another key benefit of Spanner.
  • Spanner handles all the usual types (int, double, string, arrays, enums, POCOs). There are no special cases.
  • Spanner supports modularisation via view/view-models pairs, "global" models (i.e., libraries), strongly typed templates, and use of arbitrary third-party libraries.
  • Spanner will sort all your code dependencies for you and emit modules and variable definitions in the right order.
  • Spanner provides mechanism rather than policy. As long as you are happy using Knockout for your observables, it is entirely up to you how to structure your web application.
  • Spanner makes it easy to mix hand-written JavaScript with Spanner-generated JavaScript. The two worlds work quite comfortably together, provided the non-Spanner JavaScript has a well-typed API (hah!).
  • Building happens in the blink of an eye. If you are used to waiting ages for MVC to do its thing, Spanner's instant turn-around will be a relief.
  • Normal web development is excruciating for anyone used to more sophisticated languages. You spend so much of your working day chasing down trivial bugs and the primitive languages involved practically force you to turn your code into a mess of expedient short cuts. I wrote Spanner as a reaction, to see how far I could Do It Right while using a mainstream programming language (trust me, if we all migrated to F# or Haskell, Spanner would look a lot less cunning).
  • Using Spanner will clearly make you more attractive to members of your favourite sex.
Watch this space. I have the code completed, tested, and documented. I am just putting together a web site with a tutorial and some demonstrations (as my old PhD supervisor said to me, never show an idiot something half finished :-)). Being a family man with a full time job, this may take a week or three...

Thursday, September 19, 2013

Damn you, C# !

For some time now I have been working on a pet project: a domain specific language implemented as a set of C# types intended to support the creation of complex single-page web applications, generating everything including the HTML, CSS, and JavaScript.  I am more than a little pleased with the result and will be making it open source any day now.  [My motivation for this is that I've spent the last two years immersed in the web world, which is clearly a brilliant idea implemented by psychopaths and idiots -- I will rant in more detail on this topic at some later point.]

Speaking of points, back to the subject in hand.

My DSL is, in large part, based around a type Expr<T> denoting a JavaScript expression of type T.  To make life convenient, I have added implicit casts from string to Expr<string> (etc.) and overridden the standard operator set {+, -, *, /, %, ==, !=, <, <=, etc.}.  So far so good.  I can write expressions such as x + (y * z) in my DSL directly in C# where x, y, and z are Expr<int> or Expr<double>, and so forth.

There are two flies in the ointment.

Ointment fly number 1: you can't freely overload the indexing operator.

I would like to be able to write xs[i] to denote the JavaScript expression for the ith element of the array xs.  Tragically, I can't do this.  Here's what the implementation might look like if you could:

public static Expr<T>this[Expr<int>i] { get { return ...; } }

But, noooo, I can't do this because this has to be defined in the Expr<T> class and that means this has type Expr<T> rather than Expr<T[]>, which is what is required.  Instead I have to provide some awkward named function, Ith(xs, i) to do the job.  Ugh.

Damn you, C# !

Ointment fly number 2: you can't freely overload the << operator.

I would like to express assignments in my DSL as x := y or x <- y, but I can't do that because C# won't let you create new infix operators.  Hmm, well, I reckon << is hardly ever used, so maybe I could hijack x << y instead for assignment.  It has as slightly tainted C++ flavour, but it's the best thing on offer.

But, noooo, I can't do this because if I write

public static Act operator <<(Var<T>x, Expr<T>e) { ... }

I get a complaint from the C# compiler that not only is the first argument not of type Expr<T> (the hosting class), but the second argument is not a plain old int!  Great googly moogly, what were they thinking?  Even if I wanted to implement << as bitwise left shift in my little DSL, I couldn't because of the idiotic second constraint.  Instead I have to provide some awkward named function, Set(x, e) to do the job.  Ugh.

Damn you, C# !

Why would you expect any of this to work?

I just so happens I spent most of my life doing functional programming (I taught Haskell, I worked on the Mercury language team for a very long time).  In sane, modern languages (i.e., ones invented since ~1970 by people who actually passed a few hard exams -- OO, I am not talking about you) this sort of thing is done as a matter of course.

Arghghghghghgh.