OdeToCode IC Logo

Your Abomination Is My Clever Hack

Tuesday, December 1, 2009

In the MvcContrib project there is an HTML helper for putting data into a <table>. The syntax looks like this:

<%= Html.Grid(item.Addresses)
            .Columns(column =>
                {
                    column.For(a => a.City);
                    column.For(a => a.Country);
                    column.For(a => a.Street);   
                })
            .Attributes(style => "width:100%")
            .Empty("No mailing address present!")
%>

I remember thinking this API was rather cool when Jeremy Skinner presented the syntax on his blog. The syntax became the topic of discussion in a recent Stack Overflow post - Abuse of C# lambda expressions or Syntax brilliance?

 I'm fascinated, yet at the same time repulsed, by a syntactic trick used in the Grid syntax:

.Attributes(style => "width:100%")

The syntactic trick is how the API uses the name of the lambda’s parameter as the name of the HTML attribute to set. You can set a bunch of the table attributes like this…

.Attributes(style       => "width:100%",
            id          => "grid",
            cellpadding => "0") 

…and it will render …

<table id="grid" style="width:100%" cellpadding="0">
   ....
</table>

Beautiful, don’t you think?

Bending Languages

bend I can appreciate the following thought process:

  1. How did they do that?
  2. Oh. My. Gosh.

I mean - nobody expects the name they pick for a parameter at compile time to be so important during runtime. The Stack Overflow post has a couple choice comments, including two from Eric Lippert:

This is horrid in so many ways

And …

I just asked Anders (and the rest of the design team) what they thought. Let's just say the results would not be printable in a family-friendly newspaper

I don’t think one of the goals of C# is to “be like Lisp”, but I like the code, and it reminds me of a 1993 essay by Paul Graham titled “Programming Bottom-Up”.

Experienced Lisp programmers divide up their programs differently. As well as top-down design, they follow a principle which could be called bottom-up design-- changing the language to suit the problem. In Lisp, you don't just write your program down toward the language, you also build the language up toward your program. As you're writing a program you may think "I wish Lisp had such-and-such an operator." So you go and write it.

The project I’ve worked on for the last part of the year was a huge technical challenge. I bent the hell out of C# to try and make something that was easy to read and maintain. Looking back now, I can see a lot of mistakes and plenty of room for improvement, but I also believe if the project didn’t use some tricks with extension methods and Expression<T>, we’d be facing 3x the amount of code and 3x the complexity.

Since that time I’ve become a big believer in bending languages. You have to look past the tricky implementation details and see the bigger problem being solved.