I’m pretty sure that everyone who has ever tried to create a serious LINQ provider has suffered through the same stages:
- Fascination: The way C# 3’s new features were combined to create query comprehensions are cool. Lambdas, anonymous types, extension methods, and all the rest are really useful language features on their own, and the query expression syntax (from … select) is really just a very thin layer on top of it (although they somehow managed to get Monads into the game).
- Excitement: Via IQueryable and Expression<Func<…>>, we even get ASTs for the queries we write, and we can process them to generate SQL!
- Hope: LINQ query expressions look much like SQL, so there must be a simple way to transform one into the other.
- Frustration: The Queryable class makes a big mess out of those nice-looking query expressions. As we look at more complex queries and read the C# specs, we realize that the transformation from query expressions into method invocations follows some strange rules. They are very necessary for creating expressions that can be compiled and executed in C#, but unfortunately, we get the same bloated expressions for our ASTs. Now transformation to SQL doesn’t look so simple anymore. Transparent identifiers anyone?
- Despair: System.Core does not contain any useful code to deal with those ASTs. LINQ to SQL does, but it doesn’t expose it (unfortunately, because LINQ to SQL is one oft the few LINQ providers that can deal with anything you throw at it).
- Capitulation: We settle with a simple LINQ provider that understands just a primitive subset of LINQ (and throws exceptions for everything else), or we find that other LINQ providers might be good enough.
OK, now the last point is an exaggeration. Not everyone surrenders to the complexity of LINQ, or we would not have any useful LINQ providers. But few people actually get past this point, just have a look at Frans Bouma’s 15-part series Developing Linq to LLBLGen Pro. And honestly, it’s a real PITA that everyone would have to do this from scratch.
If we look at the nice syntax that query expressions have, it’s really a pity. Why can’t we have ASTs that resemble this beautiful syntax? After all, they are so much more like anything we’d want to transform them to (except for compiled code). SQL, XQuery, NHibernate’s HQL, Entity Framework’s Entity SQL, you name it.
Starting last year, we created a LINQ infrastructure that supports our own O/R mapper (re-store), and we started from exactly this point: To reduce complexity, we’d transform LINQ ASTs back into ASTs that resemble the original query expression syntax. (In some cases this is not the original syntax, since the extension methods of Queryable can also be called directly. But in compiled code this makes no difference, so we transform everything into query expressions.)
The result is re-linq. If you are thinking about writing a LINQ provider that supports more than just from/where/select, I’d like to encourage you to take a close look at re-link. Also, do not hesitate to contact us about missing features or chances to participate. (Unfortunately, providing public access to our issue tracker and a mailing list are still on our to-do list, but supply will follow demand!)
Fabian has written a short paper about re-linq (including open issues), and we’re going to publish more information in this blog soon. Stay tuned.