Type-safe bindings

The advent of compile-time metaprogramming in C# gave birth to several interesting techniques that add extra expressivity to the type system. In this installation, we examine one of these techniques that provides a type-safe way to refer to object/class members.

One of the natural scenarios that involves type-safe bindings is programming web applications in MVC style. The following example is taken from a blog post Strongly Typed ASP.Net MVC Helpers by Sean McAlinden (take a look at the post if you wonder about the internals of this neat trick):

<% using (Html.BeginForm("Update", "Home")) { %>
  <%= Html.RenderTextBoxFor(Model, c => c.FirstName) %>
  <%= Html.RenderValidationMessageFor(Model, c => c.FirstName) %>
  <%= Html.RenderTextBoxFor(Model, c => c.LastName) %>
  <%= Html.RenderValidationMessageFor(Model, c => c.LastName) %>
<% } %>

This code snippet leverages surrogate lambdas hack to describe model properties that are bound to form widgets. This works because Render methods specify the type of the second parameter as an Expression<Func<T, U>>. Whenever C# compiler sees a function type in the context when an expression type is required, it performs automatic code lifting (i.e. transforms the body of the function into an AST).

The same effect would be achieved if Render methods were macro defs. Since macros are expanded during the compile-time, they always get ASTs that correspond to their arguments, which provides code analysis capabilities. This topic is discussed in more details in "Advanced domain-specific languages" and "Language integrated queries" case studies.

If you're inspired by this possibility, you might be delighted to know that similar functionality is already present in Scala since version 2.8 (though it has experimental status). To see how it works, let's compile and run the following code:

import scala.reflect._

object Lift extends App {
  def bind[T, U](field: Code[T => U]) =
    println(field.tree.toString)

  class Foo(val bar: Int, val baz: Int)
  bind((foo: Foo) => foo.bar)
}
Function(
  List(LocalValue(NoSymbol,foo,PrefixedType(ThisType(Class(Lift)),Class(Lift.Foo)))),
  Select(
    Ident(LocalValue(NoSymbol,foo,PrefixedType(ThisType(Class(Lift)),Class(Lift.Foo)))),
    Method(Lift.Foo.bar,NullaryMethodType(PrefixedType(ThisType(Class(scala)),Class(scala.Int))))))

For more information about Scala reflection API, take a look at the following resources: Reflecting Scala, Embedded Domain-Specific Languages Using Libraries and Dynamic Metaprogramming and reflection API in the trunk of Scala 2.10, or write directly to our mailing list at http://groups.google.com/group/scala-user.