I just got my hands on the Roslyn preview, and having six hours to wait at Seattle airport, I thought I’d have a play with it. On first impressions it is really good. You should note that the implementation is currently quite incomplete with lots of syntax not supported, but it does give a really good feel for what will be available in the future.
Roslyn is Microsoft’s effort to rewrite their C# compiler in C# – I believe the original compiler is written in C++. It’s a shame they have left it this long before doing so, as rewriting it in C# would seem to give a number of benefits. First, it proves that C# is a sufficiently good implementation language to write such things. This is no bad thing and used to be the first thing that you did in a new language. Writing the compiler allowed you to write the first big application in the language, allowing you to check out the idioms and richness of the language. Most importantly though, it makes it possible to use the compiler as a service as the managed code can be easily imported into another managed process, and if you expose enough APIs the compiler can easily be used as a service.
Let’s try some simple experiments with this new API. First we need a syntax tree for a small amount of C#. We can use the textual representation of some C# and get the Roslyn code to parse it into a syntax tree for us.
It you compile up the debug visualizer that comes in the preview, and then install that in the Visualizers directory for the Visual Studio that you are running, you get a very nice representation of the parse tree. Roslyn preserves the whitespace by adding its details as fields in the parse tree nodes. This allows your code to concentrate on the parse tree, while while still allowing the original code to be regenerated. This is very useful for writing tooling of various kinds.
Roslyn is a lot more than a syntax analyser though. The focus here is on the semantics of the languages that it processes – both C# and VB.
In order to get semantic information, we need to package up the syntax tree together with the references that are needed to compile it. We’re going to write the code out later, so we need to pass in some compilation options that say we’re creating a standalone assembly.
We access compilation information using the semantic model that is associated with the code.
Before getting the model, you should check for errors in the code using the compilations diagnostic collection. I forget to do this when experimenting and wondered why I kept getting error elements in the semantic model.
We can find the call to f. When this is compiled the compiler needs to insert some implicit conversions to convert the various int values into the longs that are needed. Using the managed C# compiler, we can get information to say that these implicit conversions are present.
We navigate the tree to find the call.
And then look at the semantic information associated with that part of the tree.
Notice how the implicit conversion is recorded in the Implicit conversion field of the information object. Note too, the Type and ConvertedType fields which record the pre- and post- conversion types.
We have a full compiler here though, so we can actually get it to write out the compiled code as an assembly.
Using Reflector, we can see the decompilation of the written module.
There are loads of samples in the preview that demonstrate the kinds of things you can do with this power. Code analysis, refactoring plus all kinds of meta-programming are going to be possible at the C# level. Meta-programming is usually done at the IL level these days using tools like Cecil. Working at the language level is going to make such transforms much easier to debug, and using the same compiler as Visual Studio itself is going to mean that your analysis tool and code generation tool agree on the syntax and semantics.
One other rather cool use of the managed C# compiler is to produce a REPL, including intellisense.
A lot of day to day programming is exploratory in nature and a REPL makes it so much easier for the user to try out ideas with instant feedback without having to go through a time consuming compile cycle (of the whole program). Understanding an API to some library class often requires some experimentation. Languages like Common Lisp have had this ability forever, and it will be interesting to see if the class-based syntax of C# keeps this a useful feature.
Unfortunately it won’t be available in the next release of Visual Studio, dev 11, which will probably be released sometime in 2012, but at least we have a flavour of where C# is going in the future.