views:

527

answers:

5

I'm looking into LINQ and the query language appears (at least on the surface) to be nothing more than an implementation of map and/or list comprehensions as found in Haskell and other FP languages (particularly the generalisation of 'map' and 'for' in Scala). Is this correct? Is there more to the syntax than this? From the breathless tone of the book I'm reading ("Essential LINQ") it would seem like there's something new or innovative here.

There's the whole back-end, pipeline, first-order expression trees and types etc to implement LINQ but my question is about the query language itself.

Cheers

Joe

+4  A: 

Besides reading a book about it, did you already used LINQ? I found it to be a huge timesaver in my daily programming work. For me, it's the next step of abstraction, which can be used to combine different datasources like XML or SQL and working with them in same "language".

Furthermore, I recommend this interview with Anders Hejlsberg about functional programming and LINQ.

Henrik P. Hessel
Thanks for the response and link, I'll read it. Yes, I have used it a bit (and I find it very useful indeed), but I used in the same way that I've been using map and for in Scala. I asked the question because of the similarities and wondered how deep they go.
Joe
+5  A: 

The breathlessness is probably intended for all that "obvious" stuff, some of which (like expression trees) is truly excellent. The language is just a means of access; do you get excited over the throw keyword, or over the functionality it exposes?

Ben M
I didn't mean the '"obvious" stuff' was obvious, simply that it was acknowledged but not the focus of my question! Perhaps I phrased it a little poorly.
Joe
Others please read Ben M's comment in light of my edit to the question.
Joe
+20  A: 

Functionally spoken, LINQ is nothing but a syntactic simplification of expressing monads. Linq to Objects (List-comprehensions - even this would already be extremely useful), which you have been talking about, is just one possible application of this (similar to the List-Monad in Haskell).

If you write

from x in expr1
from y in expr2
select x + y

it's nothing but

do
    x <- expr1
    y <- expr2
    return $ x + y

in Haskell.

The concrete thing that is done depends on user-defined Linq-providers (Extension-Methods) of which Linq.Enumerable is just one implementation involving IEnumerables.

By providing one, you can create completely new LINQ-semantics for your types.

Example: Given an Option type for computations that may fail (nullable values), one could define a Linq-provider for querying over them.

public static class MaybeExtensions
{
public static Option<T> ToMaybe<T>(this T value)
{
    return Option<T>.Some(value);
}

public static Option<U> SelectMany<T, U>(
    this Option<T> m, 
    Func<T, Option<U>> k)
{
    return !m.IsNone ? Option<U>.None : k(m.Value);
}

public static Option<V> SelectMany<T, U, V>(
    this Option<T> m, 
    Func<T, Option<U>> k, 
    Func<T, U, V> s)
{
    return m.SelectMany(x => k(x).SelectMany(y => s(x, y).ToMaybe()));
}
}

This would now allow us to write such code:

var sum = from x in ReadNumber("x")
          from y in ReadNumber("y")
          select x + y;

The computation will only return a value if all computations succeeded and will otherwise fail at the first failing one.

In combination with expression trees, Linq can be extremely powerful and allows you to express -

  1. Database accesses
  2. Asynchronous programm flow
  3. Maybe-Monads
  4. List comprehensions
  5. Recursive descent parsers
  6. Continuations
  7. Mini-languages
  8. Parallel computations (PLinq)

Some links:

Combined with fixed-point combinators, Linq provides a complete functional mini-language (Linq raytracer).

Note that Scala and F# both have similar concepts in for-comprehensions and computation expressions both being monadic abstractions:

Scala:

for (x <- expr1
     y <- expr2) yield x + y

F#:

monad {
    let! x = expr1
    let! y = expr2
    return x + y
}
Dario
Thank you for the info. I'll look into those leads.
Joe
Really, really good summary with a nice, easy to grasp example. +1
Konrad Rudolph
Continuing on the raytracer link, here's the same raytracer implemented entirely in a single LINQ statement: http://tirania.org/blog/archive/2007/Nov-16.html
JulianR
+1  A: 

LINQ was inspired by HaskellDB, as Erik Meijer has numerously stated, e.g. in Confessions of a Used Programming Language Salesman (Getting the Masses Hooked on Haskell), so it is not in itself a new concept. Using the same language to query different sources is to some extent innovative, although the fact that nested-relational model covers XML, objects, and relational databases has been shown by researchers before. For me, what's extremely cool is that it has been embedded into a popular, general-purpose, and primarily object-oriented language, which hasn't been done before.

Scala IMHO has the capacities to incorporate something similar. So far, for Scala we have Stefan Zeiger's ScalaQuery and Daniel Spiewak's ScalaQL, that follow LINQ footsteps.

Yardena
Thank you for the links, they look very interesting.
Joe
+3  A: 

The core of LINQ, the query syntax, isn't actually huge in scope. It is simply some very literal translations, to methods and lambdas - so

var qry = from x in src
          where x.Foo == "foo"
          select x.Bar;

is literally:

var qry = src.Where(x => x.Foo == "foo").Select(x => x.Bar);

It knows nothing about extension methods (although they are the most common (but not only) implementation), and nothing about Expression etc. The number of keywords (and hence the number of required method implementations) isn't huge. Jon once attempted to implement all of them in 1 hour (in a live presentation). He didn't do too badly ;-p


Perhaps the more impressive part of LINQ is the expression tree support that was required to allow LINQ to be used against databases - i.e. the lambda expression that can be compiled either to a delegate or to an object model that represents the code written. Interestingly, this same idea shines through into the way that DLR resolution works in 4.0.

Marc Gravell
A very useful perspective. Thanks for clarifying.
Joe