Fluidic APIs are stupid... NOT!
People rave about Ruby with its fancy schmancy ability to construct internal DSL's (Domain Specific Languages). The oft-touted example is: 20.minutes.ago
In .net we now have 'extension methods', which let us do all sorts of lingustic gymnastics, including 20.minutes.ago (albeit with a few extra brackets in C#) (phil haack posted an example 6.months.ago) But the examples are all a little contrived: 20.minutes.ago happens to form a logical chain where each word passes a value to the following word. But very few phrases are like that. The real question is: can we turn all of our .net code into fluidic and beautiful prose? Can we implement, for example, the Shakespeare Programming Language as an internal DSL, in C#? Here goes...
No, actually, I'm not that brave. I'm going to try something far simpler -- converting a common line of real C# into a more grammatically correct form. Here's the common line of C#: if (!this.IsPostBack)
It would translate into plain english as: "if this is not a post back"
So, subtituting spaces for dots, brackets and so on, a fluid interface might say:
if (this.is.not.a.postback))
...Can it be done?
If I went easy on myself I could change it to:
I could do it the cheaty way, and create a 'is_not_a_postback' method... but that's against the spirit of the thing.
The tricky bit is the word 'not' -- i figured it would create a clone of the object, then use reflection to visit each boolean property, and set the value to it's logical opposite. That's bad though, cause firstly "IsPostBack" is a readonly property -- so we can't reverse it (without accessing internal state... heh heh) and secondly, setting those properties might have unwanted side effects... so forget it.
At this point I could either email some of the world's greatest .net minds and get them to work on the problem around the clock while i head off to sleep. Or I could apply a model-driven architecture approach:
If the facts don't fit the model -- it's time to change the facts.
Yes, I think a more appropriate modern grammatical form of our code would be:
"if this iz a postback... NOT!!"
Now, I think I can implement that as:
if (this.iz.a.postback.__NOT__)
(again -- with a few extra empty brackets in C#)
iz,
and
a
can be implemented as what i'd term "empty non-modifier repeater extension methods" or "pass through" methods, both implemented like this:
public static Object iz(this Object obj)
{
return obj;
}
postback is a "synonymous extension method", a simple wrapper on IsPostBack:
public static bool postback(this System.Web.UI.Page pg)
{
return pg.IsPostBack ;
}
__NOT__ is "the logical inversion extension method", embellished with Textile-style __underlining__ and some nice SHOUTING.
public static bool __NOT__(this bool that)
{
return !that;
}
Now adjust your syntax highlighting so that braces and dots are the same colour as the background and we have:
if this iz a postback __NOT__
With a few more empty non-modifiers we can expand our code into the more common English form:
if this iz um
like a well um like
a youknow postback um thing
i_mean __NOT__ mkay yeh
And maybe now i see why Microsoft really added extension methods. It's bound to um, y'know like, encourage more kids to become programmers. NOT.
'Raj Chaudhuri' on Sat, 10 Nov 2007 02:22:10 GMT, sez: Mine EYES!!! They hurteth! Curses on thy evil linguistics, foul fiend!
'onur biyik' on Sat, 10 Nov 2007 08:00:37 GMT, sez: oh no, these funky C#3 features must be forbidden for lolcoders
KTHXBYE
'Josh Bush' on Sat, 10 Nov 2007 10:35:38 GMT, sez: It burns! You realize that somewhere out there someone is seeing this and thinking it's a good idea. Oh the humanity. I only hope I don't end up having to support this some day.
Thank you for not redoing the same old extension method example that everyone has done(20.<time_unit>.<point_in_time>). Even if you were just joking, you are still encouraging people to think this out a little more. I've managed 3 of these extension method examples so far on my own blog.
Thanks for the laugh. I look forward to seeing your implementation of while (stuff.is.not.finished) and for (everything.in.my.dang.list). :)
'lb' on Sat, 10 Nov 2007 10:54:10 GMT, sez: cheers Josh, Onur, Raj.
initially i was going to write about how i implemented the 20.minutes.ago extensions (had the article written up and everything) -- but then googled it and saw that this had been covered very extensively by 8 million other blogs.
such is code.
lb
'Mark Brackett' on Tue, 13 Nov 2007 10:01:33 GMT, sez: Looks like LOLCode http://lolcode.com/ implemented via Extension Methods. (Note, SubSonic has a LOLCode.NET compiler, for anyone's who's native language is AIM)
'Max Guernsey, III' on Wed, 16 Jan 2008 13:59:01 GMT, sez: I dunno... Are you joking? It seems like you are but, without inflection, it's hard to tell. I actually have no problem with the concept of "fluidic" APIs. However, I do have a problem with the way they appear to be implemented today. They seem so hacky.
For instance, the lack of a way to implement this.is.not.a.postack. The other thing that bothers me is the uncontrolled nature. It smacks of C++ templates where you had to have the headers at compile-time in order to use them.
It's nearly trivial to create a DSL proxy that supports Is.Not.A.Postback without these kinds of "parlor tricks" and the readability stays high. Consider the following:
if (PageDSL.For(this).Is.Not.A.Postback)
I'm sure you can all see how easy that would be to implement using traditional mechanisms and that it, really, isn't any less readable than the "fluidic" version.
Again, I'm not saying that "fluidic APIs" are bad, I'm saying they are still fetal and need a little more time in the oven.
-- Max
|