About

I am a software developer in Seattle, building a new AI software company.

Ads

May 2008

Sun Mon Tue Wed Thu Fri Sat
        1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31

Ads


« Office Reinvention | Main | Form versus Function in Office 12 »

September 15, 2005

LINQ, II

I have been looking at the Linq Preview under Reflector, and the more I spend time with it, the more I realize how well thought out and practical it is.

  • All queries are lazily executed. When queries are created, a tree of iterators or query objects are constructed. These queries are only processed and only return results when an enumerator is extracted in a foreach loop.
  • Queries are also "live" and reusable. If the original data source or collection changes, the results of the queries also change.
  • Xml and object implementations are both based completely on iterators. There is no Common Query Runtime involved. The object query extension methods in System.Query.Sequence are all based on iterator methods and IEnumerable<T>. The XML query extension methods are found in System.Xml.XLinq and extend IEnumerable<XElement>. The combination of extension methods, lambda expressions and iterators are powerful to match the full capabilities of XQuery.
  • Database queries are processed on the server, except for those operators not expressable in SQL in which case the inexpressable constructs are processed locally. The database query extension methods are found in System.Data.DLinq.QueryExtensions and extend Query<T> (which derives from IEnumerable<T>) with query methods that take distinguished expression trees in place of lambda expressions.

XLINQ

I feel more comfortable with the XML integration today. XElements are a lot more convenient to work with than XmlElements, currently provided by the framework. Construction is simplified through a functional notation.

Selection via XPath strings is not available as far as I can tell, but XElements do provide analogous methods. Instead of element.SelectNodes(“x//z”), one writes element.Elements(“x”).Descendants(“z”). To extract just a single node without unnecessary overhead, one simply calls First() on the result.

XElements are inheritable, so it may be possible to add some semblance of type-checking. I imagine that one can write more compact constructors this way and  also add support for object intializers and types accessors this way.

Comments

"""Queries are also "live" and reusable. If the original data source or collection changes, the results of the queries also change."""

Where is this defined? Which data sources are we talking about here?

Obviously, this isnt defined for IEnumerable, so is there another datasource for which it is?

This is actually true for IEnumerable... the .NET implementation of a lazy list.

It is true for Linq implementations of objects, XML and relational data. To eliminate deferred execution and cache the results, ToList() or ToArray() must be called.

IEnumerable returns a sequence based on the current live state of the object. Queries are deferred until a call to GetEnumerator() is made--which usually means until foreach is used.

If you use the System.Query APIs, the various functions Where, Select, OrderBy, GroupBy take an enumerable and return an enumerable that contains a pointer to the original enumerable. No call to GetEnumerator() on the original enumerable is ever made until the that of the final enumerable is called.

So, all execution is actually deferred. If the original objects are changed. That change is reflected when the next query is foreach'ed over.

The comments to this entry are closed.