Dynamic Languages 101 (Cont.)
No conversation on dynamic languages can be called complete without a nod and a tip of the hat to one of the granddaddies of all languages, Lisp, and its Emacs-hosted cousin, Scheme. Scheme, like Lisp, is conceptually a very simple language (“Everything is a list!”) with some very mind-blowing concepts to the programmer who hasn’t wandered outside of Visual Studio much. (Code is data! Data is code!)
Scheme, as they say, is a Lisp, which means that it syntactically follows many of the same conventions that Lisp does-all program statements are in lists, bounded by parentheses, giving Scheme code the chance to either interpret the list as a method call or command, or do some processing on the list before passing it elsewhere to be operated upon. It is this “meta” facility that lends Lisps (and, therefore, Scheme) much of the power that is commonly ascribed to the languages within this family.
Getting Started with Scheme
Like the other two languages we’ve seen so far, an implementation of Scheme designed specifically for the CLR-or, to be more precise, the Dynamic Language Runtime (DLR) that runs on top of the CLR and serves as the core for IronPython, IronRuby and the “dynamic” keyword in C# 4.0-is available. Not surprisingly, it is called “IronScheme” and it is available for download on Codeplex at http://ironscheme.codeplex.com in either source or precompiled binary form. Pull it down, install (or build) it, and fire up the IronScheme REPL to get a prompt to play with.
As already mentioned, everything in Lisp is a list, so all programming in Scheme will basically be putting together ()-bracketed lists of things, typically in a Polish-notation fashion. So, for example, typing the following:> (* 5 20)
Yields a response of “100” because that is what applying the “*” (multiplication) function on arguments of “5” and “20” produces.
This list-based syntax alone is fascinating because it means that Scheme can write functions that accept a varying number of parameters without significant difficulty (what the academics sometimes refer to as “flexible arity”), meaning that we can also write:> (* 5 20 20)
And get back “2000”.
Of course, if all we wanted was a reverse-reverse-Polish calculator, we’d ask some long-haired dude whose family name used to be “Niewardowski” to recite multiplication tables while walking backwards. Scheme also allows you to store values in named storage using (define):> (define pi 3.14159)
> (define radius 10)
> (* pi (* radius radius))
(define) isn’t limited to just defining variables; we can also (define) new functions, like so:> (define (square x) (* x x))
> (* pi (square radius))
One of the things apparent when we look at Scheme code is that the distinctions between “variables” and “methods” are quite fuzzy when compared against languages like C# and VB. Is “pi” a function that returns a value, or is it a variable storing a value? And, quite honestly, do we care? Should we? (You might, but you shouldn’t. Unlearn, young Jedi, unlearn.)
If there’s a theme to this article, it’s that hosting language “X” is pretty easy, and IronScheme really is no different. From a new C# Console project, add three assembly references from the IronScheme root directory: Microsoft.Scripting.dll (the DLR), IronScheme.dll, and IronScheme.Closures.dll. See Listing 3.
As you can see, getting an IronScheme engine up and running is pretty straightforward: just ask the DLR’s ScriptDomainManager to give you an IronScheme engine instance. Once there, we only need to pass the Scheme expressions in, and IronScheme will hand back the results. If those expressions resolve into functions, such as in the case above with foo, then we need only cast them to Callable instances, and we can call through to them with no difficulty.
Oh, and for the record? IronScheme is ridiculously easy to get started using on a Web MVC project, because the IronScheme authors have already built the necessary hooks (and Visual Studio integration!) to create an MVC application. In the IronScheme implementation, check out the “websample” directory, which contains a couple of different samples (as well as the IronScheme documentation). Configure an ASP.NET site around that directory, then hit it with an HTTP request of “/blog”, and explore the 100% IronScheme-written blog engine. Admittedly, it’s pretty tiny, but then again, so is the code. And the IronScheme way to represent an HTML view isn’t all that hard to read, either (Listing 4).
Although it may look a little overwhelming, when you peer into it, a number of things leap out: there is a correlation between HTML tags and Scheme functions (“(h2 ...)”, “(form ...)”, and so on), and the open-ended nature of Scheme lists makes it easy to extend the language to incorporate templatized elements into the rendered HTML.
For example, consider this snippet from the above: `(div ,@(map display-entry blogdata))
This looks pretty innocuous, but here the power of Scheme’s functional nature kicks in-we use the “map” function to take a function, display-entry, and map it over every element in the blogdata collection, which effectively iterates through the collection and generates the HTML for each entry. To those willing to look past the arcane ()-based syntax, Scheme offers all the power of a functional language, combined with the flexibility of a dynamic one.
Is this likely to take over from ASP.NET MVC written in C# or VB any time soon? Maybe not, but long-time practitioners of Lisp and Scheme have often touted how easy it is to get things done in these languages thanks to the ability to build abstractions on top of abstractions, so maybe it’s worth a research spike for a while, just to see.
No discussions of a modern Lisp would be complete without mentioning Clojure, a Lisp originally born on the JVM, but since ported to the CLR. Clojure is a Lisp, but it’s not Common Lisp or Scheme. Its creator, Rich Hickey, put some fascinating ideas about state and data into the language, making it a powerful tool for doing things in parallel. If you’re a Java programmer, picking up Clojure is a highly-recommended step to take; if you’re a .NET programmer, however, although still recommended, it’s not quite as easy, owing to the fact that all of the documentation and articles and books on Clojure are focused specifically on the JVM and Java APIs.
Still, for those willing to brace themselves for a little rough sailing at first, Clojure-CLR can be a powerful experiment, and it’s a natural complement to learning IronScheme. Clojure, unlike most Lisps, has no interpreter, meaning that Clojure-CLR is going to compile everything into IL, and thus eliminate concerns around the “hideous performance” of being an interpreted language.
Certainly the crop of .NET languages doesn’t end here. In fact, trying to trim the list down from all the languages I could have discussed was one of the hardest things about writing this article-languages like Cobra, Nemerle, Boo and the aforementioned IronPython and IronRuby, all are powerful and useful languages that can significantly change the development arc of a project if used correctly.
No one language is going to be the silver bullet to all your development ills; what we gain in using a dynamic language, we lose in taking on some of the risks inherent in that language. For example, almost every Ruby developer I’ve ever talked to makes it very clear that in a Ruby project, unit tests are not just a nice-to-have, but an essential necessity to ensuring the project succeeds. The language offers a tremendous amount of flexibility, but at a price.
At the end of the day, that’s probably something that should be said about all the tools we use. Caveat emptor.