<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://msmvps.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Jon Skeet: Coding Blog : LINQ</title><link>http://msmvps.com/blogs/jon_skeet/archive/tags/LINQ/default.aspx</link><description>Tags: LINQ</description><dc:language>en</dc:language><generator>CommunityServer 2008.5 SP2 (Build: 40407.4157)</generator><item><title>An object lesson in blogging and accuracy; was: Efficient "vote counting" with LINQ to Objects - and the value of nothing</title><link>http://msmvps.com/blogs/jon_skeet/archive/2009/09/20/efficient-quot-vote-counting-quot-with-linq-to-objects-and-the-value-of-nothing.aspx</link><pubDate>Sun, 20 Sep 2009 20:48:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1725262</guid><dc:creator>skeet</dc:creator><slash:comments>11</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/rsscomments.aspx?PostID=1725262</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/commentapi.aspx?PostID=1725262</wfw:comment><comments>http://msmvps.com/blogs/jon_skeet/archive/2009/09/20/efficient-quot-vote-counting-quot-with-linq-to-objects-and-the-value-of-nothing.aspx#comments</comments><description>&lt;p&gt;Well, this is embarrassing.&lt;/p&gt;  &lt;p&gt;Yesterday evening, I excitedly wrote a blog post about an interesting little idea for making a particular type of LINQ query (basically vote counting) efficient. It was an idea that had occurred to me a few months back, but I hadn&amp;#39;t got round to blogging about it.&lt;/p&gt;  &lt;p&gt;The basic idea was to take a completely empty struct, and use that as the element type in the results of a grouping query - as the struct was empty, it would take no space, therefore &amp;quot;huge&amp;quot; arrays could be created for no cost beyond the fixed array overhead, etc. I carefully checked that the type used for grouping did in fact implement ICollection&amp;lt;T&amp;gt; so that the Count method would be efficient; I wrote sample code which made sure my queries were valid... but I failed to check that the empty struct &lt;em&gt;really&lt;/em&gt; took up no memory.&lt;/p&gt;  &lt;p&gt;Fortunately, I have smart readers, a number of whom pointed out my mistake in very kind terms.&lt;/p&gt;  &lt;p&gt;Ben Voigt gave the reason for the size being 1 in a comment:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;The object identity rules require a unique address for each instance... identity can be shared with super- or sub- class objects (Empty Base Optimization) but the total size of the instance has to be at least 1.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;This makes perfect sense - it&amp;#39;s just a shame I didn&amp;#39;t realise it before.&lt;/p&gt;  &lt;p&gt;Live and learn, I guess - but apologies for the poorly researched post. I&amp;#39;ll attempt to be more careful next time.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1725262" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/Wacky+Ideas/default.aspx">Wacky Ideas</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/LINQ/default.aspx">LINQ</category></item><item><title>What's in a name?</title><link>http://msmvps.com/blogs/jon_skeet/archive/2009/02/27/what-s-in-a-name.aspx</link><pubDate>Fri, 27 Feb 2009 11:29:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1674533</guid><dc:creator>skeet</dc:creator><slash:comments>23</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/rsscomments.aspx?PostID=1674533</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/commentapi.aspx?PostID=1674533</wfw:comment><comments>http://msmvps.com/blogs/jon_skeet/archive/2009/02/27/what-s-in-a-name.aspx#comments</comments><description>&lt;p&gt;T.S. Eliot had the right idea when he wrote &lt;a href="http://www.americanpoems.com/poets/tseliot/5536"&gt;&amp;quot;The naming of cats&amp;quot;&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The Naming of Cats is a difficult matter,&lt;br /&gt;It isn&amp;#39;t just one of your holiday games&lt;br /&gt;...&lt;br /&gt;When you notice a cat in profound meditation,&lt;br /&gt;The reason, I tell you, is always the same:&lt;br /&gt;His mind is engaged in a rapt contemplation&lt;br /&gt;Of the thought, of the thought, of the thought of his name:&lt;br /&gt;His ineffable effable&lt;br /&gt;Effanineffable&lt;br /&gt;Deep and inscrutable singular Name.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Okay, so developers may not contemplate their &lt;em&gt;own&lt;/em&gt; names much, but I know I&amp;#39;ve certainly spent a significant amount of time recently trying to work out the &lt;em&gt;right&lt;/em&gt; name for various types and methods.&amp;nbsp; It always feels like it&amp;#39;s just out of reach; tauntingly, tantalisingly close.&lt;/p&gt;
&lt;p&gt;Recently I&amp;#39;ve been thinking a bit about what the goals might be in coming up with a good name. In particular, I seem to have been plagued with the naming problem more than usual in the last few weeks.&lt;/p&gt;
&lt;h3&gt;Operations on immutable types&lt;/h3&gt;
&lt;p&gt;A while ago I asked &lt;a href="http://stackoverflow.com/questions/521893/"&gt;a question on Stack Overflow&lt;/a&gt; about naming a method which &amp;quot;adds&amp;quot; an item to an immutable collection. Of course, when I say &amp;quot;adds&amp;quot; I mean &amp;quot;returns a new collection whose contents is the old collection and the new item.&amp;quot; There&amp;#39;s a really wide range of answers (currently 38 of them) which mostly seem to fall into four categories:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use Add because it&amp;#39;s idiomatic for .NET collections. Developers should know that the type is immutable and act accordingly.  &lt;/li&gt;
&lt;li&gt;Use Cons because that&amp;#39;s the term functional programming has used for this exact operation for decades.  &lt;/li&gt;
&lt;li&gt;Use a new method name (Plus being my favourite at the moment) which will be obvious to non-functional developers, but without being so familiar that it suggests mutability.  &lt;/li&gt;
&lt;li&gt;Use a constructor taking the old collection and the new item.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Part of the reasoning for Add being okay is that I originally posted the question purely about &amp;quot;an immutable collection&amp;quot; - e.g. a type which would have a name like ImmutableList&amp;lt;T&amp;gt;. I then revealed my &lt;em&gt;true&lt;/em&gt; intention (which I should have done from the start) - to use this in &lt;a href="http://code.google.com/p/minibench/"&gt;MiniBench&lt;/a&gt;, where the &amp;quot;collection&amp;quot; would actually be a TestSuite. Everything in MiniBench is immutable (it&amp;#39;s partly an exploration in functional programming, as it seems to fit very nicely) but I don&amp;#39;t want to have to name every single type as Immutable[Whatever]. There&amp;#39;s the argument that a developer should know at least a &lt;em&gt;little&lt;/em&gt; bit about any API they&amp;#39;re using, and the immutability aspect is one of the first things they should know. However, MiniBench is arguably an extreme case, because it&amp;#39;s &lt;em&gt;designed&lt;/em&gt; for sharing test code with people who&amp;#39;ve never seen it before.&lt;/p&gt;
&lt;p&gt;I&amp;#39;m pretty sure I&amp;#39;m going to go with Plus in the end:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It&amp;#39;s close enough to Add to be familiar  &lt;/li&gt;
&lt;li&gt;It&amp;#39;s different enough to Add to suggest that it&amp;#39;s not &lt;em&gt;quite&lt;/em&gt; the same thing as adding to a normal collection  &lt;/li&gt;
&lt;li&gt;It sounds like it returns something - a statement which &lt;em&gt;just&lt;/em&gt; calls Plus without using the result sounds like it&amp;#39;s wrong (and indeed it would be)  &lt;/li&gt;
&lt;li&gt;It&amp;#39;s meaningful to everyone  &lt;/li&gt;
&lt;li&gt;I have a precedent in the &lt;a href="http://joda-time.sourceforge.net/"&gt;Joda Time&lt;/a&gt; API&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Another option is to overload the + operator, but I&amp;#39;m not really sure I&amp;#39;m ready to do that &lt;em&gt;just&lt;/em&gt; yet. It would certainly leave brief code, but is that really the most important thing?&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s look at a situation with some of the same issues...&lt;/p&gt;
&lt;h3&gt;LINQ operators&lt;/h3&gt;
&lt;p&gt;Work on &lt;a href="http://code.google.com/p/morelinq/"&gt;MoreLINQ&lt;/a&gt; has progressed faster than expected, mostly because the project now has four members, and they&amp;#39;ve been expending quite a bit of energy on it. (I must do a proper consistency review at some point - in particular it would be nice to have the docs refer to the same concepts in the same way each time. I digress...)&lt;/p&gt;
&lt;p&gt;Most of the discussion in the project hasn&amp;#39;t been about functionality - it&amp;#39;s been about naming. In fact, LINQ is particularly odd in this respect. If I had to guess at how the time has been spent (at least for the operators I&amp;#39;ve implemented) I&amp;#39;d go for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;15% designing the behaviour  &lt;/li&gt;
&lt;li&gt;20% writing the tests  &lt;/li&gt;
&lt;li&gt;10% implementation  &lt;/li&gt;
&lt;li&gt;5% writing the documentation (just XML docs)  &lt;/li&gt;
&lt;li&gt;50% figuring out the best name&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It really is that brutal - and for a lot of the operators we still haven&amp;#39;t got the &amp;quot;right&amp;quot; name yet, in my view. There&amp;#39;s generally too much we want to convey in a word or two. As an example, we&amp;#39;ve got an operator similar to the oft-implemented ForEach one, but which yields the input sequence back out again. Basically it takes an action, and for each element it calls the action and then yields the element. The use case is something like logging. We&amp;#39;ve gone through several names, such as Pipe, Tee, Via... and just this morning I asked a colleague who suggested Apply, just off the top of his head. It&amp;#39;s better than anything we&amp;#39;d previously thought of, but does it convey both the &amp;quot;apply an action&amp;quot; and &amp;quot;still yield the original sequence&amp;quot; aspects?&lt;/p&gt;
&lt;p&gt;The old advice of &amp;quot;each method should only do one thing&amp;quot; is all very well, and it clearly helps to make naming simpler, but with situations like this one there are just &lt;em&gt;naturally&lt;/em&gt; more concepts which you want to get across in the name.&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s stay on the LINQ topic, but stray a bit further from the well-trodden path...&lt;/p&gt;
&lt;h3&gt;The heart of Push LINQ: IDataProducer&lt;/h3&gt;
&lt;p&gt;I&amp;#39;ve probably bored most of you with &lt;a href="http://msmvps.com/blogs/jon_skeet/archive/2008/01/04/quot-push-quot-linq-revisited-next-attempt-at-an-explanation.aspx"&gt;Push LINQ&lt;/a&gt; by now, and I&amp;#39;m not actively developing it at the moment, but there&amp;#39;s still one aspect which I&amp;#39;m deeply uncomfortable with: the core interface. IDataProducer represents a stream of data which can be observed. Basically clients subscribe to events, and their event handlers will be called when data is &amp;quot;produced&amp;quot; and when the stream ends.&lt;/p&gt;
&lt;p&gt;I &lt;em&gt;know&lt;/em&gt; IDataProducer is an awful name - but so far I haven&amp;#39;t found anything better. IObservable? Ick. Overused and isn&amp;#39;t descriptive. IPushEnumerable? Sounds like the client can iterate over the data, which they can&amp;#39;t. The actual event names (DataProduced/EndOfData) are okay but there &lt;em&gt;must&lt;/em&gt; be something better than IDataProducer. (Various options have been suggested in the past - none of them have been so obviously &amp;quot;right&amp;quot; as to stick in my head...)&lt;/p&gt;
&lt;p&gt;This situation is slightly different to the previous ones, however, simply because it&amp;#39;s such a pivotal type. You would think that the more important the type, the more important the name would be - but in some ways the reverse is true. You see, Push LINQ isn&amp;#39;t a terribly &amp;quot;obvious&amp;quot; framework. I say that without shame - it&amp;#39;s great at what it does, but it takes a few mental leaps before you really grok it. You&amp;#39;re really going to &lt;em&gt;have&lt;/em&gt; to read some documentation or examples before you write your own queries.&lt;/p&gt;
&lt;p&gt;Given that constraint, it doesn&amp;#39;t matter too much what the interface is called - it&amp;#39;s going to be explained to you before you need it. It doesn&amp;#39;t need to be discoverable - whereas when you&amp;#39;re picking method names to pop up in Intellisense, you really want the developer to be able to &lt;em&gt;guess&lt;/em&gt; its purpose even before they hover over it and check the documentation.&lt;/p&gt;
&lt;p&gt;I haven&amp;#39;t given up on IDataProducer (and I hope to be moving Push LINQ into MoreLINQ, by the way - working out a better name is one of the blockers) but it doesn&amp;#39;t feel like &lt;em&gt;quite&lt;/em&gt; as much of a problem.&lt;/p&gt;
&lt;h3&gt;Read-only or not read-only?&lt;/h3&gt;
&lt;p&gt;This final example came up at work, just yesterday - after I&amp;#39;d started writing this post. I wanted to refactor some code to emphasize which methods only use the read-only side of an interface. This was purely for the sake of readability - I wanted to make it easier to reason about which areas of the code modified an object and which didn&amp;#39;t. It&amp;#39;s a custom collection - the details don&amp;#39;t matter, but for the sake of discussion let&amp;#39;s call it House and pretend we&amp;#39;re modelling the various things which might be in a house. (This is Java, hence House rather than IHouse.)&lt;/p&gt;
&lt;p&gt;I&amp;#39;m explicitly &lt;em&gt;not&lt;/em&gt; doing this for safety - I don&amp;#39;t mind the fact that the reference could be cast to a mutable interface. The point is just to make it self-documenting that if a method only has a parameter in the non-mutating form, it&amp;#39;s not going to change the contents of the house.&lt;/p&gt;
&lt;p&gt;So, we have two interfaces, like this:&lt;/p&gt;
&lt;div class="code"&gt;&lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span class="Type"&gt;interface&lt;/span&gt; NameMePlease&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Color getDoorColor();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Type"&gt;int&lt;/span&gt; getWindowCount();&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="InlineComment"&gt;// This already returned a read-only collection&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Set&amp;lt;Furniture&amp;gt; getFurniture();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span class="Type"&gt;interface&lt;/span&gt; House extends NameMePlease&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Type"&gt;void&lt;/span&gt; setDoorColor(Color doorColor);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Type"&gt;void&lt;/span&gt; setWindowCount(&lt;span class="Type"&gt;int&lt;/span&gt; windows);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Type"&gt;void&lt;/span&gt; addFurniture(Furniture item);&lt;br /&gt;} &lt;/div&gt;
&lt;p&gt;Obviously the challenge is to find a name for NameMePlease. One option is to use something like ImmutableHouse or ReadOnlyHouse - but the inheritance hierarchy makes liars of both of those names. How can it be a ReadOnlyHouse if there are methods in an implementation which change it? The interface should say what you &lt;em&gt;can&lt;/em&gt; do with the type, rather than specifying what you &lt;em&gt;can&amp;#39;t&lt;/em&gt; do - unless part of the contract of the interface is that the implementation will genunely prohibit changes.&lt;/p&gt;
&lt;p&gt;Thinking of this &amp;quot;positive&amp;quot; aspect led me to ReadableHouse, which is what I&amp;#39;ve gone with for the moment. It states what you can do with it - read information. Again, this is a concept which Joda Time uses.&lt;/p&gt;
&lt;p&gt;Another option is to make it just House, and change the mutable interface to MutableHouse or something similar. In this particular situation the refactoring involved would have been enormous. Simple to automate, but causing a huge check-in for relatively little benefit. Almost all uses are &lt;em&gt;actually&lt;/em&gt; mutating ones. The consensus within the Google Java mailing list seems to be that this would have been the preferred option, all things being equal. One interesting data point was that although Joda Time uses ReadableInstant etc, the current proposals for the new date/time API which will be included in Java 7, designed by the author of Joda Time, &lt;em&gt;don&amp;#39;t&lt;/em&gt; use this convention. Presumably the author found it didn&amp;#39;t work quite as well as he&amp;#39;d hoped, although I don&amp;#39;t have know of any specific problems.&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;You&amp;#39;ll probably be unsurprised to hear that I don&amp;#39;t have a recipe for coming up with good names. However, in thinking about naming I&amp;#39;ve at least worked out a few points to think about:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Context is important: how discoverable does this need to be? Is accuracy more important than brevity? Do you have any example uses (e.g. through tests) which can help to see whether the code feels right or not?  &lt;/li&gt;
&lt;li&gt;Think of your audience. How familiar will they be with the rest of the code you&amp;#39;re writing? Are they likely to have a background in other areas of computer science where you could steal terminology? Can you make your name consistent with other common frameworks they&amp;#39;re likely to use? The reverse is true too: are you reusing a familiar name for a &lt;em&gt;different&lt;/em&gt; concept, which could confuse readers?  &lt;/li&gt;
&lt;li&gt;Work out the information the name is trying to convey. For types, this includes working out how it participates in inheritance. Is it trying to advertise capabilities or restrictions?  &lt;/li&gt;
&lt;li&gt;Is it possible to make correct code look correct, and buggy code look wrong? This is rarely feasible, but it&amp;#39;s one of the main attractions of &amp;quot;Plus&amp;quot; in the benchmark case. (I believe this is one of the main selling points of true Hungarian Notation for variable naming, by the way. I&amp;#39;m not generally a fan, but I like this aspect.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I may expand this list over time...&lt;/p&gt;
&lt;p&gt;I think it&amp;#39;s fitting to close with a &lt;a href="http://people.famouswhy.com/phil_karlton/"&gt;quote from Phil Karlton&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There are only two hard things in Computer Science: cache invalidation and naming things.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Almost all of us have to handle naming things. Let&amp;#39;s hope most of us don&amp;#39;t have to mess with cache invalidation as well.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1674533" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/Java/default.aspx">Java</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/General/default.aspx">General</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/LINQ/default.aspx">LINQ</category></item><item><title>Designing LINQ operators</title><link>http://msmvps.com/blogs/jon_skeet/archive/2009/01/23/designing-linq-operators.aspx</link><pubDate>Fri, 23 Jan 2009 23:40:39 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1665190</guid><dc:creator>skeet</dc:creator><slash:comments>16</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/rsscomments.aspx?PostID=1665190</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/commentapi.aspx?PostID=1665190</wfw:comment><comments>http://msmvps.com/blogs/jon_skeet/archive/2009/01/23/designing-linq-operators.aspx#comments</comments><description>&lt;p&gt;I&amp;#39;ve started a small project (I&amp;#39;ll post a link when I&amp;#39;ve actually got something worthwhile to show) with some extra LINQ operators in - things which I think are missing from LINQ to Objects, basically. (I hope to include many of the ideas from an &lt;a href="http://msmvps.com/blogs/jon_skeet/archive/2008/10/23/what-other-enumerable-extension-methods-would-you-like-to-see.aspx"&gt;earlier blog post&lt;/a&gt;.) That, and a few Stack Overflow questions where I&amp;#39;ve effectively written extra LINQ operators and compared them with other solutions, have made me think about the desirable properties of a LINQ operator - or at least the things you should think about when implementing one. My thoughts so far:&lt;/p&gt; &lt;h3&gt;Lazy/eager execution&lt;/h3&gt; &lt;p&gt;If you&amp;#39;re returning a sequence (i.e. another IEnumerable&amp;lt;T&amp;gt; or similar) the execution should almost certainly be lazy, but the parameter checking should be eager. Unfortunately with the &lt;a href="http://msmvps.com/blogs/jon_skeet/archive/2008/03/02/c-4-idea-iterator-blocks-and-parameter-checking.aspx"&gt;limitations of the (otherwise wonderful) C# iterator blocks&lt;/a&gt;, this usually means breaking the method into two, like this:&lt;/p&gt; &lt;div class="code"&gt;&lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span class="Modifier"&gt;static&lt;/span&gt; IEnumerable&amp;lt;T&amp;gt; Where(&lt;span class="Keyword"&gt;this&lt;/span&gt; IEnumerable&amp;lt;T&amp;gt; source,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Func&amp;lt;T, &lt;span class="ValueType"&gt;bool&lt;/span&gt;&amp;gt; predicate)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="InlineComment"&gt;// Eagerly executed&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;if&lt;/span&gt; (source == &lt;span class="Keyword"&gt;null&lt;/span&gt;)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;throw&lt;/span&gt;&amp;nbsp;&lt;span class="Keyword"&gt;new&lt;/span&gt; ArgumentNullException(&lt;span class="String"&gt;&amp;quot;source&amp;quot;&lt;/span&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;if&lt;/span&gt; (predicate == &lt;span class="Keyword"&gt;null&lt;/span&gt;)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;throw&lt;/span&gt;&amp;nbsp;&lt;span class="Keyword"&gt;new&lt;/span&gt; ArgumentNullException(&lt;span class="String"&gt;&amp;quot;predicate&amp;quot;&lt;/span&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;return&lt;/span&gt; WhereImpl(source, predicate);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="Modifier"&gt;private&lt;/span&gt;&amp;nbsp;&lt;span class="Modifier"&gt;static&lt;/span&gt; IEnumerable&amp;lt;T&amp;gt; WhereImpl(IEnumerable&amp;lt;T&amp;gt; source,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Func&amp;lt;T, &lt;span class="ValueType"&gt;bool&lt;/span&gt;&amp;gt; predicate)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="InlineComment"&gt;// Lazily executed&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;foreach&lt;/span&gt; (T element &lt;span class="Statement"&gt;in&lt;/span&gt; source)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;if&lt;/span&gt; (predicate(element))&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;yield&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;return&lt;/span&gt; element;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;} &lt;/div&gt; &lt;p&gt;Obviously aggregates and conversions (Max, ToList etc) are generally eager anyway, within normal LINQ to Objects. (Just about everything in Push LINQ is lazy. They say pets look like their owners...)&lt;/p&gt; &lt;h3&gt;Streaming/buffering&lt;/h3&gt; &lt;p&gt;One of my favourite features of LINQ to Objects (and one which doesn&amp;#39;t get nearly the publicity of deferred execution) is that many of the operators &lt;em&gt;stream&lt;/em&gt; the data. In other words, they only consume data when they absolutely have to, and they yield data as soon as they can. This means you can process vast amounts of data with very little memory usage, so long as you use the right operators. Of course, not every operator can stream (reversing requires buffering, for example) but where it&amp;#39;s possible, it&amp;#39;s really handy.&lt;/p&gt; &lt;p&gt;Unfortunately, the streaming/buffering nature of operators isn&amp;#39;t well documented in MSDN - and sometimes it&amp;#39;s completely wrong. As I&amp;#39;ve &lt;a href="http://msmvps.com/blogs/jon_skeet/archive/2008/09/09/logging-enumeration-flow.aspx"&gt;noted before&lt;/a&gt;, the &lt;a href="http://msdn.microsoft.com/en-us/library/system.linq.enumerable.intersect.aspx"&gt;docs for Enumerable.Intersect&lt;/a&gt; claim that it reads the &lt;em&gt;whole&lt;/em&gt; of both sequences (&lt;em&gt;first&lt;/em&gt; then &lt;em&gt;second&lt;/em&gt;) before yielding any data. In fact it reads and buffers the whole of &lt;em&gt;second&lt;/em&gt;, then streams &lt;em&gt;first&lt;/em&gt;, yielding intersecting elements as it goes. I strongly encourage new LINQ operators to document their streaming/buffering behaviour (accurately!). This will limit future changes in the implementation admittedly (Intersect can be implemented in a manner where both inputs are streamed, for example) but in this case I think the extra guarantees provided by the documentation make up for that restriction.&lt;/p&gt; &lt;h3&gt;Once-only evaluation&lt;/h3&gt; &lt;p&gt;When I said that reversing requires buffering earlier on, I was sort of lying. Here&amp;#39;s an implementation of Reverse which doesn&amp;#39;t buffer any data anywhere:&lt;/p&gt; &lt;div class="code"&gt;&lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span class="Modifier"&gt;static&lt;/span&gt; IEnumerable&amp;lt;T&amp;gt; StreamingReverse&amp;lt;T&amp;gt;(&lt;span class="Keyword"&gt;this&lt;/span&gt; IEnumerable&amp;lt;T&amp;gt; source)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="InlineComment"&gt;// Error checking omitted for brevity&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="ValueType"&gt;int&lt;/span&gt; count = source.Count();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;for&lt;/span&gt; (&lt;span class="ValueType"&gt;int&lt;/span&gt; i = count-1; i &amp;gt;= 0; i--)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;yield&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;return&lt;/span&gt; source.ElementAt(i);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;} &lt;/div&gt; &lt;p&gt;If we assume we can read the sequence as often as we like, then we never need to buffer anything - just treat it as a random-access list. I hope I don&amp;#39;t have to tell you that&amp;#39;s a really, &lt;em&gt;really&lt;/em&gt; bad idea. Leaving aside the blatant inefficiency even for sequences like lists which are cheap to iterate over, some sequences are inherently once-only (think about reading from a network stream) and some are inherently costly to iterate over (think about lines in a big log file - or the result of an ordering).&lt;/p&gt; &lt;p&gt;I suspect that developers using LINQ operators &lt;em&gt;assume&lt;/em&gt; that they&amp;#39;ll only read the input data once. That&amp;#39;s a good assumption - wherever possible, we ought to make sure that it&amp;#39;s correct, and if we absolutely can&amp;#39;t help evaluating a sequence twice (and I can&amp;#39;t remember any times when I&amp;#39;ve really wanted to do that) we should document it in large, friendly letters.&lt;/p&gt; &lt;h3&gt;Mind your complexity&lt;/h3&gt; &lt;p&gt;In some ways, this falls out of &amp;quot;try to stream, and try to only read once&amp;quot; - if you&amp;#39;re not storing any data and you&amp;#39;re only reading each item once, it&amp;#39;s quite hard to come up with an operator which &lt;em&gt;isn&amp;#39;t&lt;/em&gt; just O(n) for a single sequence. It is worth thinking about though - particularly as most of the LINQ operators &lt;em&gt;can&lt;/em&gt; work with large amounts of data. For example, to find the smallest element in a sequence you can &lt;em&gt;either&lt;/em&gt; sort the whole sequence and take the first element of the result &lt;em&gt;or&lt;/em&gt; you can keep track of a &amp;quot;current minimum&amp;quot; and iterate through the whole sequence. Clearly the latter saves a lot of complexity (and doesn&amp;#39;t require buffering) - so don&amp;#39;t just take the first idea that comes into your head. (Or at least, start with that and then think how you could improve it.)&lt;/p&gt; &lt;p&gt;Again, documenting the complexity of the operator is a good idea, and call particular attention to anything which is &lt;em&gt;unintuitively&lt;/em&gt; expensive.&lt;/p&gt; &lt;h3&gt;Conclusion&lt;/h3&gt; &lt;p&gt;Okay, so there&amp;#39;s nothing earth-shattering here. But the more I use LINQ to answer Stack Overflow questions, and the more I invent new operators in the &lt;em&gt;spirit&lt;/em&gt; of the existing ones, the more powerful I think it is. It&amp;#39;s amazing how powerful it can be, and how ridiculously simple the code (sometimes) looks afterwards. It&amp;#39;s not like the operator implementation is usually hard, either - it&amp;#39;s just a matter of thinking of the right concepts. I&amp;#39;m going to try to follow these principles when I implement my extra operator library, and I hope you&amp;#39;ll bear them in mind too, should you ever feel that LINQ to Objects doesn&amp;#39;t have &lt;em&gt;quite&lt;/em&gt; the extension method you need...&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1665190" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/LINQ/default.aspx">LINQ</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/CSharpDevCenter/default.aspx">CSharpDevCenter</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/CSharpDev/default.aspx">CSharpDev</category></item><item><title>You don't have to use query expressions to use LINQ</title><link>http://msmvps.com/blogs/jon_skeet/archive/2009/01/07/you-don-t-have-to-use-query-expressions-to-use-linq.aspx</link><pubDate>Wed, 07 Jan 2009 17:32:24 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1658790</guid><dc:creator>skeet</dc:creator><slash:comments>18</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/rsscomments.aspx?PostID=1658790</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/commentapi.aspx?PostID=1658790</wfw:comment><comments>http://msmvps.com/blogs/jon_skeet/archive/2009/01/07/you-don-t-have-to-use-query-expressions-to-use-linq.aspx#comments</comments><description>&lt;p&gt;LINQ is clearly gaining a fair amount of traction, given the number of posts I see about it on &lt;a href="http://stackoverflow.com"&gt;Stack Overflow&lt;/a&gt;. However, I&amp;#39;ve noticed an interesting piece of coding style: a lot of developers are using query expressions for &lt;em&gt;every&lt;/em&gt; bit of LINQ they write, however trivial.&lt;/p&gt; &lt;p&gt;Now, don&amp;#39;t get the wrong idea - I love query expressions as a helpful piece of syntactic sugar. For instance, I&amp;#39;d always pick the query expression form over the &amp;quot;dot notation&amp;quot; form for something like this:&lt;/p&gt; &lt;div class="code"&gt;&lt;span class="Linq"&gt;var&lt;/span&gt; query = &lt;span class="Linq"&gt;from&lt;/span&gt; file &lt;span class="Statement"&gt;in&lt;/span&gt; Directory.GetFiles(logDirectory, &lt;span class="String"&gt;&amp;quot;*.log&amp;quot;&lt;/span&gt;)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;from&lt;/span&gt; line &lt;span class="Statement"&gt;in&lt;/span&gt;&amp;nbsp;&lt;span class="Keyword"&gt;new&lt;/span&gt; LineReader(file)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;let&lt;/span&gt; entry = &lt;span class="Keyword"&gt;new&lt;/span&gt; LogEntry(line)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;where&lt;/span&gt; entry.Severity == Severity.Error&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;select&lt;/span&gt; file + &lt;span class="String"&gt;&amp;quot;: &amp;quot;&lt;/span&gt; + entry.Message; &lt;/div&gt; &lt;p&gt;(Yes, it&amp;#39;s yet another log entry example - it&amp;#39;s one of my favourite demos of LINQ, and particularly Push LINQ.) The equivalent code using just the extension methods would be pretty ugly, especially given the various range variables and transparent identifiers involved.&lt;/p&gt; &lt;p&gt;However, look at &lt;em&gt;these&lt;/em&gt; two queries instead:&lt;/p&gt; &lt;div class="code"&gt;&lt;span class="Linq"&gt;var&lt;/span&gt; query = &lt;span class="Linq"&gt;from&lt;/span&gt; person &lt;span class="Statement"&gt;in&lt;/span&gt; people&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;where&lt;/span&gt; person.Salary &amp;gt; 10000m&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;select&lt;/span&gt; person;&lt;br /&gt;&lt;br /&gt;&lt;span class="Linq"&gt;var&lt;/span&gt; dotNotation = people.Where(person =&amp;gt; person.Salary &amp;gt; 10000m); &lt;/div&gt; &lt;p&gt;In this case, we&amp;#39;re just making a single method call. Why bother with three lines of query expression? If the query becomes more complicated later, it can easily be converted into a query expression at that point. The two queries are &lt;em&gt;exactly&lt;/em&gt; the same, even though the syntax is different.&lt;/p&gt; &lt;p&gt;My guess is that there&amp;#39;s a &amp;quot;black magic&amp;quot; fear of LINQ - many developers know how to write query expressions, but aren&amp;#39;t confident about what they&amp;#39;re converted into (or even the basics of what the translation process is like in the first place). Most of the C# 3.0 and LINQ books that I&amp;#39;ve read &lt;em&gt;do&lt;/em&gt; cover query expression translation to a greater or lesser extent, but it&amp;#39;s rarely given much prominence.&lt;/p&gt; &lt;p&gt;I suspect the black magic element is reinforced by the inherent &amp;quot;will it work?&amp;quot; factor of LINQ to SQL - you get to write the query in your favourite language, but you may well not be confident in it working until you&amp;#39;ve tried it; there will always be plenty of little gotchas which can&amp;#39;t be picked up at compile time. With LINQ to Objects, there&amp;#39;s a lot more certainty (at least in my experience). However, the query expression translation &lt;em&gt;shouldn&amp;#39;t&lt;/em&gt; be part of what developers are wary of. It&amp;#39;s clearly defined in the spec (not that I&amp;#39;m suggesting that all developers should learn it via the spec) and benefits from being relatively dumb and therefore easy to predict.&lt;/p&gt; &lt;p&gt;So next time you&amp;#39;re writing a query expression, take a look at it afterwards - if it&amp;#39;s simple, try writing it without the extra syntactic sugar. It may just be sweet enough on its own.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1658790" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/LINQ/default.aspx">LINQ</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/CSharpDevCenter/default.aspx">CSharpDevCenter</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/CSharpDev/default.aspx">CSharpDev</category></item><item><title>November 19th: London .NET User Group, Push LINQ!</title><link>http://msmvps.com/blogs/jon_skeet/archive/2008/11/07/november-19th-london-net-user-group-push-linq.aspx</link><pubDate>Fri, 07 Nov 2008 21:51:23 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1653448</guid><dc:creator>skeet</dc:creator><slash:comments>6</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/rsscomments.aspx?PostID=1653448</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/commentapi.aspx?PostID=1653448</wfw:comment><comments>http://msmvps.com/blogs/jon_skeet/archive/2008/11/07/november-19th-london-net-user-group-push-linq.aspx#comments</comments><description>&lt;p&gt;On November 19th, I&amp;#39;ll be speaking at the &lt;a href="http://dnug.org.uk/"&gt;London .NET User Group&lt;/a&gt; about Push LINQ. I was quite pleasantly surprised by being able to explain it to some extent in Copenhagen, and this evening will be entirely about Push LINQ, so I&amp;#39;ll be able to go into a lot more detail. &lt;a href="http://skillsmatter.com/"&gt;Skills Matter&lt;/a&gt; will be hosting the event (near Farringdon station). It starts at 6.30pm, and &lt;a href="http://skillsmatter.com/event/open-source-dot-net/london-dot-net-ug-meeting"&gt;registration is now open&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;Should be fun. Please come and heckle.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1653448" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/LINQ/default.aspx">LINQ</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/Speaking+engagements/default.aspx">Speaking engagements</category></item><item><title>What other Enumerable extension methods would you like to see?</title><link>http://msmvps.com/blogs/jon_skeet/archive/2008/10/23/what-other-enumerable-extension-methods-would-you-like-to-see.aspx</link><pubDate>Thu, 23 Oct 2008 20:50:39 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1651783</guid><dc:creator>skeet</dc:creator><slash:comments>25</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/rsscomments.aspx?PostID=1651783</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/commentapi.aspx?PostID=1651783</wfw:comment><comments>http://msmvps.com/blogs/jon_skeet/archive/2008/10/23/what-other-enumerable-extension-methods-would-you-like-to-see.aspx#comments</comments><description>&lt;p&gt;A few questions on Stack Overflow have suggested to me that there might be some bits missing from LINQ to Objects. There&amp;#39;s the idea of a &amp;quot;zip&amp;quot; operator, which pairs up two sequences, for instance. Or the ability to apply the set operators with projections, e.g. &lt;code&gt;DistinctBy&lt;/code&gt;, &lt;code&gt;IntersectBy&lt;/code&gt; etc (mirroring &lt;code&gt;OrderBy&lt;/code&gt;). They&amp;#39;re easy to implement, but it would be nice to get a list of what people would like to see.&lt;/p&gt; &lt;p&gt;So, what&amp;#39;s missing?&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1651783" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/LINQ/default.aspx">LINQ</category></item><item><title>DeveloperDeveloperDeveloper: Registration now open (hurry!)</title><link>http://msmvps.com/blogs/jon_skeet/archive/2008/10/22/developerdeveloperdeveloper-registration-now-open-hurry.aspx</link><pubDate>Wed, 22 Oct 2008 09:53:34 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1651598</guid><dc:creator>skeet</dc:creator><slash:comments>4</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/rsscomments.aspx?PostID=1651598</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/commentapi.aspx?PostID=1651598</wfw:comment><comments>http://msmvps.com/blogs/jon_skeet/archive/2008/10/22/developerdeveloperdeveloper-registration-now-open-hurry.aspx#comments</comments><description>&lt;p&gt;The &lt;a href="http://msevents.microsoft.com/CUI/EventDetail.aspx?EventID=1032393874&amp;amp;Culture=en-GB"&gt;registration page for DeveloperDeveloperDeveloper Day 2008&lt;/a&gt; (Reading, November 22nd) is now open. In the past this has been heavily oversubscribed, so if you want to come you&amp;#39;ll need to register quickly.&lt;/p&gt; &lt;p&gt;I&amp;#39;ve got a speaking slot in the afternoon: implementing LINQ to Objects in 60 minutes. As always, I&amp;#39;m very much looking forward to it.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1651598" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/LINQ/default.aspx">LINQ</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/CSharpDevCenter/default.aspx">CSharpDevCenter</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/CSharpDev/default.aspx">CSharpDev</category></item><item><title>DotNetRocks interview</title><link>http://msmvps.com/blogs/jon_skeet/archive/2008/10/07/dotnetrocks-interview.aspx</link><pubDate>Tue, 07 Oct 2008 16:33:49 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1650011</guid><dc:creator>skeet</dc:creator><slash:comments>5</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/rsscomments.aspx?PostID=1650011</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/commentapi.aspx?PostID=1650011</wfw:comment><comments>http://msmvps.com/blogs/jon_skeet/archive/2008/10/07/dotnetrocks-interview.aspx#comments</comments><description>&lt;p&gt;Last Monday evening I had a chat with the guys from &lt;a href="http://dotnetrocks.com"&gt;DotNetRocks&lt;/a&gt;, and today &lt;a href="http://www.dotnetrocks.com/default.aspx?showNum=383"&gt;the show has gone live&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;I wouldn&amp;#39;t claim to have said anything &lt;em&gt;particularly&lt;/em&gt; earth-shattering, and regular readers will probably be familiar with many of the themes anyway, but I thoroughly enjoyed it and hope you will too. Amongst other things, we talked about:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Protocol buffers&lt;/li&gt; &lt;li&gt;Implicit typing and anonymous types&lt;/li&gt; &lt;li&gt;Why it doesn&amp;#39;t bother me that Office hasn&amp;#39;t been ported to .NET&lt;/li&gt; &lt;li&gt;C# 4&lt;/li&gt; &lt;li&gt;My wishlist for C#&lt;/li&gt; &lt;li&gt;Threading and Parallel Extensions&lt;/li&gt; &lt;li&gt;Working for Google&lt;/li&gt; &lt;li&gt;How to learn LINQ&lt;/li&gt; &lt;li&gt;C# in Depth&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Feedback welcome. And yes, I know I sound somewhat like a stereotypical upper-class idiot at times. Unfortunately there&amp;#39;s not a lot I can do about that. Only the &amp;quot;idiot&amp;quot; part is accurate :)&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1650011" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/General/default.aspx">General</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/C_2300_+4/default.aspx">C# 4</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/LINQ/default.aspx">LINQ</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/Parallelisation/default.aspx">Parallelisation</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/Google/default.aspx">Google</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/Protocol+Buffers/default.aspx">Protocol Buffers</category></item><item><title>Book review: Pro LINQ - Language Integrated Query in C# 2008, by Joe Rattz</title><link>http://msmvps.com/blogs/jon_skeet/archive/2008/09/22/book-review-pro-linq-language-integrated-query-in-c-2008-by-joe-rattz.aspx</link><pubDate>Mon, 22 Sep 2008 00:57:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1648553</guid><dc:creator>skeet</dc:creator><slash:comments>16</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/rsscomments.aspx?PostID=1648553</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/commentapi.aspx?PostID=1648553</wfw:comment><comments>http://msmvps.com/blogs/jon_skeet/archive/2008/09/22/book-review-pro-linq-language-integrated-query-in-c-2008-by-joe-rattz.aspx#comments</comments><description>&lt;p&gt;I&amp;#39;m trying something slightly different this time. Joe (the author) has reacted to specific points of my review, and I think it makes sense to show those reactions. I&amp;#39;d originally hoped to present them so that you could toggle them on or off, but this blog server apparently wants to strip out scripts etc, so the comments are now permanently visible.&lt;/p&gt;
&lt;h3&gt;Resources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Buy from &lt;a href="http://www.amazon.com/dp/1590597893"&gt;Amazon&lt;/a&gt; or &lt;a href="http://search.barnesandnoble.com/Pro-LINQ/Joseph-C-Rattz/e/9781590597897"&gt;Barnes and Noble&lt;/a&gt;  &lt;/li&gt;
&lt;li&gt;&lt;a href="http://linqdev.com/"&gt;Author&amp;#39;s web site&lt;/a&gt;  &lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.apress.com/book/view/1590597893"&gt;Apress page&lt;/a&gt; (errata submissions etc)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Introduction and disclaimer&lt;/h3&gt;
&lt;p&gt;As usual, I first need to give the disclaimer that as the author of a somewhat-competing book, I may be biased and certainly will have different criteria to most people. In this case the competition aspect is less direct than normal - this book is &amp;quot;LINQ with the C# 3 bits as necessary&amp;quot; whereas my book is &amp;quot;C# 2 and 3 with LINQ API where necessary&amp;quot;. However, it&amp;#39;s still perfectly possible that a potential reader may try to choose between the two books and buy just one. If you&amp;#39;re in that camp, I suggest you &lt;span style="text-decoration:line-through;"&gt;buy my book&lt;/span&gt; try to find an impartial opinion instead of trusting my review.&lt;/p&gt;
&lt;p&gt;A second disclaimer is needed this time: I didn&amp;#39;t buy my copy of this book; it was sent to me by Apress at the request of Joe Rattz, specifically for review (and because Joe&amp;#39;s a nice guy). I hope readers of my other reviews will be confident that this won&amp;#39;t change the honest nature of the review; where there are mistakes or possible improvements, I&amp;#39;m happy to point them out.&lt;/p&gt;
&lt;h3&gt;Content, audience and overall approach&lt;/h3&gt;
&lt;p&gt;This book is simply aimed at existing C# developers who want to learn LINQ. There&amp;#39;s an assumption that you&amp;#39;re already reasonably confident in C# 2 - knowledge of generics is taken as read, for example - but there &lt;em&gt;is&lt;/em&gt; brief coverage of using iterator blocks to return sequences. No prior experience of LINQ is required, but the LINQ to XML and LINQ to SQL sections assume (not unreasonably) that you already know XML and SQL.&lt;/p&gt;
&lt;p&gt;The book is divided into five parts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Introduction and C# 3.0 features (50 pages) &lt;/li&gt;
&lt;li&gt;LINQ to Objects (130 pages) &lt;/li&gt;
&lt;li&gt;LINQ to XML (152 pages) &lt;/li&gt;
&lt;li&gt;LINQ to DataSet (42 pages) &lt;/li&gt;
&lt;li&gt;LINQ to SQL (204 pages)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The approach to the subject matter changes somewhat through the book. Sometimes it&amp;#39;s a concept-by-concept &amp;quot;tutorial style&amp;quot; approach, but for most of the book (particularly the LINQ to Objects and LINQ to XML parts) it reads more like an API reference. Joe recommends that readers tackle the book from cover to cover, but that falls down a bit in the more reference-oriented sections.&lt;/p&gt;
&lt;div class="reaction"&gt;
&lt;p&gt;[Joe] Early in the development of my book, a friend asked me if it was going to be a tutorial-style book or a reference book.  I initially found the question odd because I never really viewed books as being exclusively one or the other. Perhaps I am different than most readers, but when I buy a programming book, I usually read a bit, start coding, and then refer to the book as a reference when needed.  This is how I envision my book being used by readers and the type of book I would like for it to be.  I see it as both a tutorial and a reference.  I want it to be a book that gets used repeatedly, not read once and shelved.  Some books work better for this than others.  I rarely read a programming book cover to cover because I just don&amp;#39;t have time for that.  I think ultimately, most authors write the book they would want to read, and that is what I did. I hope that if someone buys my book, in two years it will be tattered and worn from use as a reference, as well as read cover to cover.&lt;/p&gt;
&lt;p&gt;I would disagree that the majority of the book reads like an API reference.  Certainly, chapters 4 and 5 (deferred and nondeferred operators) work better as a reference because there isn&amp;#39;t a lot of connective context between the approximately 50 different standard query operators.  At best it would be an eclectic tutorial with little continuity.  So I decided to make those two chapters (the ones covering the standard query operators) function more like a reference. I knew that I (and hopefully my readers) would refer to it time and time again for information about the operators, and based on most of the reviews I have seen, this appears to have been a good choice. I know I refer to it myself quite frequently.  I would not consider the chapters on LINQ to XML to be reference oriented although I could see why someone might feel they are.  My discussion of LINQ to XML is tutorial based as I approach the different tasks a developer would need to accomplish when working with XML, such as how to construct XML, how to output XML, how to input XML, how to traverse XML, etc.  However, within a task, like traversing XML, I do list the API calls and discuss them, so this is probably why it feels reference-like to some readers, and will function pretty well as a reference.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;For example, take the ordering operators in LINQ - OrderBy, ThenBy, OrderByDescending and ThenByDescending. (Interestingly, one of the Amazon reviews picks up on the same example. I already had it in mind before reading that review.) These four LINQ to Objects operators take 15 pages to cover because every method overload is used, but a lot of it is effectively repeated between different examples. I think more depth could have been achieved in a shorter space by talking about the group as a whole - we only really need to see what happens when a custom comparison is used once, not four times - whereas every example of ThenBy/ThenByDescending used an identity projection, instead of showing how you can make the secondary ordering use some completely different projection (without necessarily using a custom comparer). Likewise I don&amp;#39;t remember seeing anything about tertiary orderings, or what the descending orderings tend to do with nulls, or emphasis on the fact that descending orderings aren&amp;#39;t just reversed ascending orderings (due to the stability of the sort - the stability was mentioned, but not this important corollary). Having an example for each overload is useful for a reference work, but not for a &amp;quot;read through from start to finish&amp;quot; book.&lt;/p&gt;
&lt;p&gt;The set operators (Distinct, Except, Intersect, Union and SequenceEqual) as applied to DataSets suffer a similar problem - the five descriptions of why custom comparers are needed are all basically the same, and could be dealt with once. In particular, one paragraph is repeated &lt;em&gt;verbatim&lt;/em&gt; for each operator. Again, that&amp;#39;s fine for a reference - but cutting and pasting like this makes for an irritating read when you see the exact same text several times in one reading session.&lt;/p&gt;
&lt;div class="reaction"&gt;
&lt;p&gt;[Joe] A few readers have complained about some of the redundancies that you have pointed out, but I think most of the readers have appreciated my attempt to provide material for each operator/method.  I think one of the words you will see most often in the Amazon reviews is &amp;quot;thorough&amp;quot;.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Now, it&amp;#39;s important that I don&amp;#39;t give the wrong impression here. This is certainly not &lt;em&gt;just&lt;/em&gt; a reference book, and there&amp;#39;s enough introduction to topics to help readers along. If I&amp;#39;d been coming to C# 3 and LINQ without any other information, I think I&amp;#39;d have followed things, for the most part. (I&amp;#39;m not a fan of the way Joe presented the query expression translations, but I&amp;#39;m enormously pleased that he did it at all. I think I might have got lost at that point, which was unfortunately early in the book. It might have been better as just an appendix.) Anyone reading the book thoroughly should come away with a competent knowledge of LINQ and the ability to use it profitably. They may well be less comfortable with the new features of C# 3, as they&amp;#39;re only covered briefly - but that&amp;#39;s entirely appropriate given the title and target of the book. (To be blunt and selfish, I&amp;#39;m entirely in favour of books which leave room for more depth at a language level - that should be a good thing for sales of my own book!)&lt;/p&gt;
&lt;div class="reaction"&gt;
&lt;p&gt;[Joe] Jon, if you only knew how difficult it was getting those query expression translations into the book. ;-) You can read in my acknowledgments where I specifically thank Katie Stence and her team for them.  They were a very painful effort and in hindsight, I probably would not include them if I were to start the book from scratch. I agree with you that the translations are complex, as the book states.  Perhaps the most important part of that section is when I state &amp;quot;Allow me to provide a word of warning.  The soon to be described translation steps are quite complicated.  Do not allow this to discourage you.  You no more need to fully understand the translation steps to write LINQ queries than you need to know how the compiler translates the foreach statement to use it. They are here to provide additional translation information should you need it, which should be rarely, or never.&amp;quot;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;However, I would personally have preferred to see a more conceptual approach which spent more time focused on getting the ideas through at a deep level and less time making sure that every overload was covered. After all, MSDN does a reasonable job as a reference - and the book&amp;#39;s web site could have contained an example for every overload if necessary without everything making it into print. The kind of thing I&amp;#39;d have liked to see explored more fully is the buffering vs streaming nature of data flow in LINQ. Some operators - Select and Where, for example - stream all their data through. They never keep look at more than one item of data at a time. Others (Reverse and OrderBy, for example) have to buffer up &lt;em&gt;all&lt;/em&gt; the data in the sequence before yielding &lt;em&gt;any&lt;/em&gt; of it. Still others use two sequences, and may buffer one sequence and stream the other - Join and Intersect work that way at the moment, although as we saw in &lt;a href="http://msmvps.com/blogs/jon_skeet/archive/2008/09/09/logging-enumeration-flow.aspx"&gt;my last blog post&lt;/a&gt; Intersect can be implemented in a way which streams both sequences (but still needs to keep a buffer of data it&amp;#39;s already seen). When you&amp;#39;re working with an infinite (or perhaps just very large - much bigger than memory) sequence you really need to be aware of this distinction, but it isn&amp;#39;t covered in Pro LINQ as far as I remember. In the interests of balance, I should point out that the difference between immediate and deferred execution &lt;em&gt;is&lt;/em&gt; explained, repeatedly and clearly - including the semi-immediate execution which can occur sometimes in LINQ to SQL.&lt;/p&gt;
&lt;div class="reaction"&gt;
&lt;p&gt;[Joe] I wanted my book to cover each overload because I can&amp;#39;t read MSDN in the bathroom, or when at the beach without an internet connection, or when curled up in a chair by the fireplace.  I also wanted to provide examples for every method and overload because I find it frustrating when a book shows the simplest one and I have to figure out the one I need.  Granted, depth could be added too, but you have to draw the line somewhere.  Apress (at the time, not sure if this is still the plan) has the concept of three levels of book; Foundations, Pro, and Expert.  I considered some information beyond the scope of the Pro level that my book is aimed at.  The buffering versus streaming issue is an interesting one and would make an excellent additional column in Table 3-1, if I can get it to fit.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;I&amp;#39;m unable to really judge the depth to which LINQ to SQL was explored, given that a lot of it was beyond my own initial knowledge (which is a good thing!). I&amp;#39;m slightly perturbed by the idea that it can be comprehensively tackled in a couple of hundred pages, whereas books on other ORMs are often &lt;em&gt;much&lt;/em&gt; bigger and tackle topics such as session lifetimes and caching in much more depth. I suspect this is more due to the technologies than the writing here - LINQ to SQL is a relatively feature-poor ORM compared with, say, Hibernate - but a bit more attention to &amp;quot;here are options to consider when writing an application&amp;quot; would have been welcome.&lt;/p&gt;
&lt;h3&gt;Accuracy and code style&lt;/h3&gt;
&lt;p&gt;Most of Pro LINQ is pretty accurate. Joe is occasionally a bit off in terms of terminology, but that probably bothers most readers less than it bothers me. There are a few things which changed between the beta version of VS2008 against which the book was clearly developed and the release version, which affect the new features of C# 3. For instance, automatically implemented properties aren&amp;#39;t mentioned at all (and would have been much nicer to see in examples than public fields) and collection initializers are described with the old restrictions (the collection type has to implement ICollection&amp;lt;T&amp;gt;) rather than the new ones (the collection type has to implement IEnumerable and have appropriate Add methods). Other errors include trusting the documentation too much (witness the behaviour of Intersect) and an inconsistency (stating correctly that OrderBy is stable on one page, then incorrectly warning that it&amp;#39;s unstable on another). In my normal fashion, I&amp;#39;ll give Joe an exhaustive list of everything I&amp;#39;ve found and leave it up to him to see which he&amp;#39;d like to fix for the next printing, but overall Pro LINQ does pretty well. I suspect this may be &lt;em&gt;partly&lt;/em&gt; due to covering a great deal of area but with relatively little depth and some repetition - Accelerated C# had a higher error rate, but was delving into more treacherous waters, for example.&lt;/p&gt;
&lt;div class="reaction"&gt;
&lt;p&gt;[Joe] Since my book is not meant to be a C# 3.0 book, but rather a LINQ book, I only cover the new C# 3.0 features which were added to support LINQ.  Since automatic properties were not one of those features, I do not cover them. You may notice that my chapter dedicated to the new C# 3.0 features is titled C# 3.0 Language Enhancements For LINQ.  Just for your reader&amp;#39;s knowledge, the ordering is now specified to be stable.  Initially it was unstable, and was later changed to be stable but I was told it would be specified to be unstable, but apparently at some point, the specification was changed to be stable.  My book was updated but apparently I missed a spot.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Most of the advice given throughout the book is reasonable, although I take issue with one significant area. Joe recommends using the OfType operator instead of the Cast operator, because when a nongeneric collection contains the &amp;quot;wrong type of object,&amp;quot; OfType will silently skip it whereas Cast will throw an exception. I recommend using Cast for exactly the same reason! If I&amp;#39;ve got an object of an unexpected type in my collection, I want to know about it &lt;em&gt;as soon as possible&lt;/em&gt;. Throwing an exception tells me what&amp;#39;s going on immediately, instead of hiding the problem. It&amp;#39;s usually the better behaviour, unless you &lt;em&gt;explicitly&lt;/em&gt; have reason to believe that you will legitimately have objects of different types in the collection and you really want to only find objects of the specified type.&lt;/p&gt;
&lt;div class="reaction"&gt;
&lt;p&gt;[Joe] Yes, I should have known better than to provide that advice (prefer OfType to Cast) without more explanation, more disclaimers, and more caveats. My preference would be to use Cast in development and debug built code for the exact reasons you mention, but to use OfType in production code. I would prefer my applications to handle unexpected data more gracefully in production than I would in development.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;As well as &amp;quot;headline&amp;quot; pieces of advice which are advertised right up to the table of contents, there are many hints and tips along the way, most of which really do add value. I believe they&amp;#39;d actually add &lt;em&gt;more&lt;/em&gt; value if they weren&amp;#39;t sometimes buried within reference-like material - but as we&amp;#39;ve already seen, my personal preference is for a more narrative style of book anyway.&lt;/p&gt;
&lt;p&gt;The code examples are in &amp;quot;snippet&amp;quot; form (i.e. without &lt;code&gt;using&lt;/code&gt; directives, Main method declarations etc) but are complete aside from that. At the start of each chapter there&amp;#39;s a detailed list of which namespaces and references are involved, so there&amp;#39;s no guesswork required. In fact, I&amp;#39;d expect most of them to work in Snippy given an appropriate environment. Some examples are a bit longwinded - we only really need to see the 7 lines showing the list of presidents once or twice, not over and over again - but that&amp;#39;s a minor issue. Another niggle is Joe&amp;#39;s choices when it comes to a few bits of coding convention. There are various areas where we differ, but a few repeatedly bothered me: overuse (to my mind) of parentheses, &amp;quot;old-style&amp;quot; delegate creation (i.e. something.Click += new EventHandler(Foo) instead of just something.Click += Foo) and the explicit specification of type parameters on LINQ operators which don&amp;#39;t need them. Here&amp;#39;s one example which demonstrates the first and the last of these issues - as well as introducing an unnecessary cast:&lt;/p&gt;
&lt;div class="code"&gt;&lt;span class="InlineComment"&gt;// This is the code in the book (in listing 7-30)&lt;/span&gt;&lt;br /&gt;XElement outOfPrintParticipant = xDocument&lt;br /&gt;&amp;nbsp; .Element(&lt;span class="String"&gt;&amp;quot;BookParticipants&amp;quot;&lt;/span&gt;)&lt;br /&gt;&amp;nbsp; .Elements(&lt;span class="String"&gt;&amp;quot;BookParticipant&amp;quot;&lt;/span&gt;)&lt;br /&gt;&amp;nbsp; .Where(e =&amp;gt; ((&lt;span class="ReferenceType"&gt;string&lt;/span&gt;)((XElement)e).Element(&lt;span class="String"&gt;&amp;quot;FirstName&amp;quot;&lt;/span&gt;)) == &lt;span class="String"&gt;&amp;quot;Joe&amp;quot;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;amp;&amp;amp; ((&lt;span class="ReferenceType"&gt;string&lt;/span&gt;)((XElement)e).Element(&lt;span class="String"&gt;&amp;quot;LastName&amp;quot;&lt;/span&gt;)) == &lt;span class="String"&gt;&amp;quot;Rattz&amp;quot;&lt;/span&gt;)&lt;br /&gt;&amp;nbsp; .Single&amp;lt;XElement&amp;gt;();&lt;br /&gt;&lt;br /&gt;&lt;span class="InlineComment"&gt;// This is what I&amp;#39;d have preferred&lt;/span&gt;&lt;br /&gt;XElement outOfPrintParticipant = xDocument&lt;br /&gt;&amp;nbsp; .Element(&lt;span class="String"&gt;&amp;quot;BookParticipants&amp;quot;&lt;/span&gt;)&lt;br /&gt;&amp;nbsp; .Elements(&lt;span class="String"&gt;&amp;quot;BookParticipant&amp;quot;&lt;/span&gt;)&lt;br /&gt;&amp;nbsp; .Where(e =&amp;gt; (&lt;span class="ReferenceType"&gt;string&lt;/span&gt;)e.Element(&lt;span class="String"&gt;&amp;quot;FirstName&amp;quot;&lt;/span&gt;) == &lt;span class="String"&gt;&amp;quot;Joe&amp;quot;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;amp;&amp;amp; (&lt;span class="ReferenceType"&gt;string&lt;/span&gt;)e.Element(&lt;span class="String"&gt;&amp;quot;LastName&amp;quot;&lt;/span&gt;) == &lt;span class="String"&gt;&amp;quot;Rattz&amp;quot;&lt;/span&gt;)&lt;br /&gt;&amp;nbsp; .Single(); &lt;/div&gt;
&lt;p&gt;Check out the penultimate line of the original - a whopping 5 opening brackets and 6 closing ones. This issue looks even worse to me when it&amp;#39;s used to make &lt;code&gt;return&lt;/code&gt; and &lt;code&gt;throw&lt;/code&gt; look like method calls:&lt;/p&gt;
&lt;div class="code"&gt;&lt;span class="InlineComment"&gt;// From GetStringFromDb (P388)&lt;/span&gt;&lt;br /&gt;&lt;span class="Statement"&gt;throw&lt;/span&gt; (&lt;span class="Keyword"&gt;new&lt;/span&gt; Exception(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; String.Format(&lt;span class="String"&gt;&amp;quot;Unexpected exception executing query [{0}].&amp;quot;&lt;/span&gt;, sqlQuery)));&lt;br /&gt;&lt;br /&gt;&lt;span class="InlineComment"&gt;// (Insert more code here) - same listing&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Statement"&gt;return&lt;/span&gt; (result); &lt;/div&gt;
&lt;p&gt;These just look odd and wrong. Of course they&amp;#39;re perfectly valid, but not pleasant to read in my view. On a more minor matter, Joe tends to close SQL connections, commands etc with an explicit &lt;code&gt;try&lt;/code&gt;/&lt;code&gt;finally&lt;/code&gt; block instead of the more idiomatic (to my mind) &lt;code&gt;using&lt;/code&gt; statement, but again that probably bothers me more than others.&lt;/p&gt;
&lt;p&gt;The source code is all available on the web site, and it&amp;#39;s easy to find each listing. (The zip file is about 10 times larger than it needs to be because it contains all the bin/obj directories with all the compiled code in rather than just the source, but that&amp;#39;s a tiny niggle.)&lt;/p&gt;
&lt;h3&gt;Writing style&lt;/h3&gt;
&lt;p&gt;Joe&amp;#39;s writing style is very informal - or at least, while most of the text is in &amp;quot;normal&amp;quot; formal prose, there are plenty of informal pieces of writing there too. As readers of my book will know, I&amp;#39;m much the same - I try to keep things from getting &lt;em&gt;too&lt;/em&gt; dry, despite that being the natural state for technical teaching. I have no idea how well &lt;em&gt;I&lt;/em&gt; succeed for most readers, but Joe certainly manages. He occasionally takes it a little too far for my personal taste, usually around listing outputs. They&amp;#39;re often introduced as if Joe didn&amp;#39;t really know what the output would be, with a kind of &amp;quot;wow, it worked, who&amp;#39;d have thought?&amp;quot; comment afterwards. I suspect I&amp;#39;ve got some of this in my book too, but Joe lays it on a little too thickly for my liking. I don&amp;#39;t know whether it would be fairer to present a &amp;quot;medium-level&amp;quot; example of this rather than one which really grated, but this is the one (from page 257) made such an impression that I remembered it over 300 pages later:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This should output the language attribute. Let&amp;#39;s see:&lt;/p&gt;
&lt;hr /&gt;
&lt;pre&gt;language=&amp;quot;English&amp;quot;&lt;/pre&gt;
&lt;hr /&gt;
&lt;p&gt;Groovy! I have never actually written the word &lt;i&gt;groovy&lt;/i&gt; before. I had to let the spelling checker spell it for me.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Now, I really want to stress that that&amp;#39;s a &amp;quot;worst case&amp;quot; rather than the average case, and indeed many listings don&amp;#39;t have &lt;em&gt;anything&lt;/em&gt; &amp;quot;cutesy&amp;quot; about them. I just wanted to give an example of the kind of thing that didn&amp;#39;t work for me.&lt;/p&gt;
&lt;div class="reaction"&gt;
&lt;p&gt;[Joe] Let me see if I get this straight.  So you are saying you got to learn something about LINQ and how to spell groovy, and it stuck for over 300 pages and you are upset? Man, you know how to spell groovy now, what&amp;#39;s the problem?  8-D  Would it annoy you less if I told you that is a reference to Austin Powers?  My book is riddled with references to movies and TV shows, and that one is for Austin Powers.  Maybe you didn&amp;#39;t catch that, or maybe you don&amp;#39;t like Austin Powers, or maybe you just still don&amp;#39;t like it.  One reader was irritated when I said &amp;quot;Dude, Sweet&amp;quot; because he didn&amp;#39;t recognize that as a reference to Dude, Where&amp;#39;s My Car.  I have references to Office Space, Arrested Development, Bottle Rocket, Seinfeld, The Matrix, Wargames, Tron, etc.  In fact, on page 455, I actually use the word &amp;quot;moo&amp;quot; instead of &amp;quot;moot&amp;quot; in reference to Friends.  My copy editor actually corrected that for me, but once I explained it, she let me have it back.  So if you see something goofy, like &amp;quot;groovy&amp;quot; just know it is a reference to something and begin your investigation in your spare time.  And if you see an error, it is intentional to make sure you are paying attention.  ;-)  As you have already pointed out, technical writing can be dry.  I made an effort to inject humor into the book in the form of references to pop culture, most specifically movies and television.  Sometimes the reference is in a comment like &amp;quot;groovy&amp;quot;, and sometimes it&amp;#39;s in the sample data like a character&amp;#39;s name.  Like any comedian, every joke or reference can&amp;#39;t be a hit with everyone.  I will say though that I have heard more from those that recognized the references and appreciated them (which helps carry a reader through the lesser interesting parts) than I have from those that found them annoying.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;What really &lt;em&gt;did&lt;/em&gt; work was including hints and tips which explicitly said where Joe had received unexpected results with slightly different code. If anything is unexpected to the author, it may well be unexpected to readers too, so I really appreciated reading that sort of thing. (It would be wearing if Joe were stupid and expected all kinds of silly results, but that&amp;#39;s not the case at all.)&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;Pro LINQ is a good book. It has enough niggles to keep me from using superlatives about it, but it&amp;#39;s good nonetheless. It&amp;#39;s Joe&amp;#39;s first book (just like C# in Depth is the first one I can truly call &amp;quot;mine&amp;quot;) and I hope he writes more. Having read it from cover to cover, I think it&amp;#39;ll be more useful as a reference for individual methods (when MSDN doesn&amp;#39;t quite cut it) than to reread whole chapters, but that&amp;#39;s not a problem. My slight complaints above certainly don&amp;#39;t stop it from being a book I&amp;#39;m pleased to own.&lt;/p&gt;
&lt;div class="reaction"&gt;
&lt;p&gt;[Joe] I&amp;#39;ll take it as a compliment that you think my book would be useful for those times that MSDN isn&amp;#39;t good enough!&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;This is the first LINQ book I&amp;#39;ve reviewed - I already have LINQ in Action, which is also on the list to review at some point. (I&amp;#39;ve read large chunks of it in soft copy, but I haven&amp;#39;t been through the finished hard copy yet.) It will be interesting to see how the two compare. Next up will probably be &amp;quot;Programming C# 3.0&amp;quot; by Jesse Liberty, however.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1648553" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/LINQ/default.aspx">LINQ</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/Book+reviews/default.aspx">Book reviews</category></item><item><title>Logging enumeration flow</title><link>http://msmvps.com/blogs/jon_skeet/archive/2008/09/09/logging-enumeration-flow.aspx</link><pubDate>Tue, 09 Sep 2008 07:18:45 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1647209</guid><dc:creator>skeet</dc:creator><slash:comments>12</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/rsscomments.aspx?PostID=1647209</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/commentapi.aspx?PostID=1647209</wfw:comment><comments>http://msmvps.com/blogs/jon_skeet/archive/2008/09/09/logging-enumeration-flow.aspx#comments</comments><description>&lt;p&gt;I&amp;#39;m currently reading &lt;a href="http://www.amazon.com/dp/1590597893"&gt;Pro LINQ: Language Integrated Query in C# 2008&lt;/a&gt; by Joe Rattz and yesterday I came across a claim about &lt;code&gt;Enumerable.Intersect&lt;/code&gt; which didn&amp;#39;t quite ring true. I consulted MSDN and the documentation is exactly the same as the book. Here&amp;#39;s what it says:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;When the object returned by this method is enumerated, Intersect enumerates &lt;i&gt;first&lt;/i&gt;, collecting all distinct elements of that sequence. It then enumerates &lt;i&gt;second&lt;/i&gt;, marking those elements that occur in both sequences. Finally, the marked elements are yielded in the order in which they were collected. &lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;(&lt;i&gt;first&lt;/i&gt; is the first parameter, the one which the method appears to be called on when using it as an extension method. &lt;em&gt;second&lt;/em&gt; is the second parameter - the other sequence involved.)&lt;/p&gt; &lt;p&gt;This seems to be needlessly restrictive. In particular, it doesn&amp;#39;t allow you to work with an infinite sequence on either side. It also means loading the whole of both sequences into memory at the same time. Given the way that &lt;code&gt;Join&lt;/code&gt; works, I was surprised to see this. So I thought I&amp;#39;d test it. This raised the question of how you trace the flow of a sequence - how do you know when data is being pulled from it? The obvious answer is to create a new sequence which fetches from the old one, logging as it goes. Fortunately this is really easy to implement: &lt;/p&gt; &lt;div class="code"&gt;&lt;span class="Namespace"&gt;using&lt;/span&gt; System;&lt;br /&gt;&lt;span class="Namespace"&gt;using&lt;/span&gt; System.Collections.Generic;&lt;br /&gt;&lt;br /&gt;&lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span class="Modifier"&gt;static&lt;/span&gt;&amp;nbsp;&lt;span class="ReferenceType"&gt;class&lt;/span&gt; Extensions&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span class="Modifier"&gt;static&lt;/span&gt; IEnumerable&amp;lt;T&amp;gt; WithLogging&amp;lt;T&amp;gt;(&lt;span class="Keyword"&gt;this&lt;/span&gt; IEnumerable&amp;lt;T&amp;gt; source, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="ReferenceType"&gt;string&lt;/span&gt; name)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;foreach&lt;/span&gt; (T element &lt;span class="Statement"&gt;in&lt;/span&gt; source)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Console.WriteLine(&lt;span class="String"&gt;&amp;quot;{0}: {1}&amp;quot;&lt;/span&gt;, name, element);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;yield&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;return&lt;/span&gt; element;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;} &lt;/div&gt; &lt;p&gt;We keep a name for the sequence so we can easily trace which sequence is being pulled from at what point. Now let&amp;#39;s apply this logging to a call to &lt;code&gt;Intersect&lt;/code&gt;: &lt;/p&gt; &lt;div class="code"&gt;&lt;span class="Namespace"&gt;using&lt;/span&gt; System;&lt;br /&gt;&lt;span class="Namespace"&gt;using&lt;/span&gt; System.Linq;&lt;br /&gt;&lt;span class="Namespace"&gt;using&lt;/span&gt; System.Collections.Generic;&lt;br /&gt;&lt;br /&gt;&lt;span class="InlineComment"&gt;// Compile alongside the Extensions class&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="ReferenceType"&gt;class&lt;/span&gt; Test&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Modifier"&gt;static&lt;/span&gt;&amp;nbsp;&lt;span class="ValueType"&gt;void&lt;/span&gt; Main()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;var&lt;/span&gt; first = Enumerable.Range(1, 5).WithLogging(&lt;span class="String"&gt;&amp;quot;first&amp;quot;&lt;/span&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;var&lt;/span&gt; second = Enumerable.Range(3, 5).WithLogging(&lt;span class="String"&gt;&amp;quot;second&amp;quot;&lt;/span&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;foreach&lt;/span&gt; (&lt;span class="ValueType"&gt;int&lt;/span&gt; i &lt;span class="Statement"&gt;in&lt;/span&gt; first.Intersect(second))&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Console.WriteLine(&lt;span class="String"&gt;&amp;quot;Intersect: {0}&amp;quot;&lt;/span&gt;, i);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;} &lt;/div&gt; &lt;p&gt;As you can see, we&amp;#39;re intersecting the numbers 1-5 with the numbers 3-7 - the intersection should clearly be 3-5. We&amp;#39;ll see a line of output each time data is pulled from either &lt;code&gt;first&lt;/code&gt; or &lt;code&gt;second&lt;/code&gt;, and also when the result of &lt;code&gt;Intersect&lt;/code&gt; yields a value. Given the documentation and the book, one would expect to see this output: &lt;/p&gt; &lt;div class="output"&gt;&lt;span class="Attention"&gt;// Theoretical output. It doesn&amp;#39;t really do this&lt;/span&gt;&lt;br /&gt;first: 1&lt;br /&gt;first: 2&lt;br /&gt;first: 3&lt;br /&gt;first: 4&lt;br /&gt;first: 5&lt;br /&gt;second: 3&lt;br /&gt;second: 4&lt;br /&gt;second: 5&lt;br /&gt;second: 6&lt;br /&gt;second: 7&lt;br /&gt;Intersect: 3&lt;br /&gt;Intersect: 4&lt;br /&gt;Intersect: 5&lt;/div&gt; &lt;p&gt;Fortunately, it &lt;i&gt;actually&lt;/i&gt; works exactly how I&amp;#39;d expect: the second sequence is evaluated fully, then the first is evaluated in a streaming fashion, with results being yielded as they&amp;#39;re found. (This means that, if you&amp;#39;re sufficiently careful with the result, e.g. by calling &lt;code&gt;Take&lt;/code&gt; with a suitably small value, the first sequence can be infinite.) Here&amp;#39;s the actual output demonstrating that:  &lt;div class="output"&gt;&lt;span class="Attention"&gt;// Actual output.&lt;/span&gt;&lt;br /&gt;second: 3&lt;br /&gt;second: 4&lt;br /&gt;second: 5&lt;br /&gt;second: 6&lt;br /&gt;second: 7&lt;br /&gt;first: 1&lt;br /&gt;first: 2&lt;br /&gt;first: 3&lt;br /&gt;Intersect: 3&lt;br /&gt;first: 4&lt;br /&gt;Intersect: 4&lt;br /&gt;first: 5&lt;br /&gt;Intersect: 5&lt;/div&gt; &lt;h3&gt;Initial Conclusion&lt;/h3&gt; &lt;p&gt;There are two interesting points here, to my mind. The first is demonstrating that the documentation for &lt;code&gt;Intersect&lt;/code&gt; is wrong - the real code is more sensible than the docs. That&amp;#39;s not as important as seeing how easy it is to log the flow of sequence data - as simple as adding a single extension method and calling it. (You could do it with a &lt;code&gt;Select&lt;/code&gt; projection which writes the data and then yields the value of course, but I think this is neater.) &lt;/p&gt; &lt;p&gt;I&amp;#39;m hoping to finish reading Joe&amp;#39;s book this week, and write the review over the weekend, by the way.&lt;/p&gt; &lt;h3&gt;Update (Sept. 11th 2008)&lt;/h3&gt; &lt;p&gt;Frederik Siekmann replied to this post with a thrilling alternative implementation to stream the intersection, which takes alternating elements from the two sequences involved. It&amp;#39;s a bit more memory hungry (with three sets of elements to remember instead of just one) but it means that we can deal with two infinite streams, if we&amp;#39;re careful. Here&amp;#39;s a complete example:&lt;/p&gt; &lt;div class="code"&gt;&lt;span class="Namespace"&gt;using&lt;/span&gt; System;&lt;br /&gt;&lt;span class="Namespace"&gt;using&lt;/span&gt; System.Collections.Generic;&lt;br /&gt;&lt;span class="Namespace"&gt;using&lt;/span&gt; System.Linq;&lt;br /&gt;&lt;br /&gt;&lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span class="Modifier"&gt;static&lt;/span&gt;&amp;nbsp;&lt;span class="ReferenceType"&gt;class&lt;/span&gt; Extensions&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span class="Modifier"&gt;static&lt;/span&gt; IEnumerable&amp;lt;T&amp;gt; AlternateIntersect&amp;lt;T&amp;gt;(&lt;span class="Keyword"&gt;this&lt;/span&gt; IEnumerable&amp;lt;T&amp;gt; first, IEnumerable&amp;lt;T&amp;gt; second)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;var&lt;/span&gt; intersection = &lt;span class="Keyword"&gt;new&lt;/span&gt; HashSet&amp;lt;T&amp;gt;();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;var&lt;/span&gt; firstSet = &lt;span class="Keyword"&gt;new&lt;/span&gt; HashSet&amp;lt;T&amp;gt;();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;var&lt;/span&gt; secondSet = &lt;span class="Keyword"&gt;new&lt;/span&gt; HashSet&amp;lt;T&amp;gt;();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Namespace"&gt;using&lt;/span&gt; (IEnumerator&amp;lt;T&amp;gt; firstEnumerator = first.GetEnumerator())&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Namespace"&gt;using&lt;/span&gt; (IEnumerator&amp;lt;T&amp;gt; secondEnumerator = second.GetEnumerator())&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="ValueType"&gt;bool&lt;/span&gt; firstHasValues = firstEnumerator.MoveNext();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="ValueType"&gt;bool&lt;/span&gt; secondHasValues = secondEnumerator.MoveNext();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;while&lt;/span&gt; (firstHasValues &amp;amp;&amp;amp; secondHasValues)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; T currentFirst = firstEnumerator.Current;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; T currentSecond = secondEnumerator.Current;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;if&lt;/span&gt; (!intersection.Contains(currentFirst) &amp;amp;&amp;amp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; secondSet.Contains(currentFirst))&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; intersection.Add(currentFirst);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;yield&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;return&lt;/span&gt; currentFirst;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; firstSet.Add(currentFirst);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;if&lt;/span&gt; (!intersection.Contains(currentSecond) &amp;amp;&amp;amp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; firstSet.Contains(currentSecond))&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; intersection.Add(currentSecond);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;yield&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;return&lt;/span&gt; currentSecond;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; secondSet.Add(currentSecond);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; firstHasValues = firstEnumerator.MoveNext();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; secondHasValues = secondEnumerator.MoveNext();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;if&lt;/span&gt; (firstHasValues)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;do&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; T currentFirst = firstEnumerator.Current;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;if&lt;/span&gt; (!intersection.Contains(currentFirst) &amp;amp;&amp;amp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; secondSet.Contains(currentFirst))&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; intersection.Add(currentFirst);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;yield&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;return&lt;/span&gt; currentFirst;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;span class="Statement"&gt;while&lt;/span&gt; (firstEnumerator.MoveNext());&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;if&lt;/span&gt; (secondHasValues)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;do&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; T currentSecond = secondEnumerator.Current;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;if&lt;/span&gt; (!intersection.Contains(currentSecond) &amp;amp;&amp;amp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; firstSet.Contains(currentSecond))&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; intersection.Add(currentSecond);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;yield&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;return&lt;/span&gt; currentSecond;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } &lt;span class="Statement"&gt;while&lt;/span&gt; (secondEnumerator.MoveNext());&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span class="Modifier"&gt;static&lt;/span&gt; IEnumerable&amp;lt;T&amp;gt; WithLogging&amp;lt;T&amp;gt;(&lt;span class="Keyword"&gt;this&lt;/span&gt; IEnumerable&amp;lt;T&amp;gt; source, &lt;span class="ReferenceType"&gt;string&lt;/span&gt; name)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;foreach&lt;/span&gt; (T element &lt;span class="Statement"&gt;in&lt;/span&gt; source)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Console.WriteLine(&lt;span class="ReferenceType"&gt;string&lt;/span&gt;.Format(&lt;span class="String"&gt;&amp;quot;{0}: {1}&amp;quot;&lt;/span&gt;, name, element));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;yield&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;return&lt;/span&gt; element;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="ReferenceType"&gt;class&lt;/span&gt; Test&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Modifier"&gt;static&lt;/span&gt;&amp;nbsp;&lt;span class="ValueType"&gt;void&lt;/span&gt; Main()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;var&lt;/span&gt; positiveIntegers = Enumerable.Range(0, &lt;span class="ValueType"&gt;int&lt;/span&gt;.MaxValue);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;var&lt;/span&gt; multiplesOfTwo = positiveIntegers.Where(x =&amp;gt; (x%2) == 0)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; .WithLogging(&lt;span class="String"&gt;&amp;quot;Twos&amp;quot;&lt;/span&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;var&lt;/span&gt; multiplesOfThree = positiveIntegers.Where(x =&amp;gt; (x%3) == 0)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; .WithLogging(&lt;span class="String"&gt;&amp;quot;Threes&amp;quot;&lt;/span&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;foreach&lt;/span&gt; (&lt;span class="ValueType"&gt;int&lt;/span&gt; x &lt;span class="Statement"&gt;in&lt;/span&gt; multiplesOfTwo.AlternateIntersect(multiplesOfThree).Take(10))&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Console.WriteLine (&lt;span class="String"&gt;&amp;quot;AlternateIntersect: {0}&amp;quot;&lt;/span&gt;, x);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;} &lt;/div&gt; &lt;p&gt;Most of the code is the alternating intersection - the test at the end just shows intersection of the sequence 2, 4, 6, 8... with 3, 6, 9, 12... The output shows elements being taken from both sequences, and yielded when a match is found. It&amp;#39;s important that we limit the output in some way - in the above code we call &lt;code&gt;Take(10)&lt;/code&gt; but anything which prevents the loop from just executing until we run out of memory is fine.&lt;/p&gt; &lt;div class="output"&gt;Twos: 0&lt;br /&gt;Threes: 0&lt;br /&gt;AlternateIntersect: 0&lt;br /&gt;Twos: 2&lt;br /&gt;Threes: 3&lt;br /&gt;Twos: 4&lt;br /&gt;Threes: 6&lt;br /&gt;Twos: 6&lt;br /&gt;Threes: 9&lt;br /&gt;AlternateIntersect: 6&lt;br /&gt;Twos: 8&lt;br /&gt;Threes: 12&lt;br /&gt;Twos: 10&lt;br /&gt;Threes: 15&lt;br /&gt;Twos: 12&lt;br /&gt;Threes: 18&lt;br /&gt;AlternateIntersect: 12&lt;br /&gt;Twos: 14&lt;br /&gt;Threes: 21&lt;br /&gt;Twos: 16&lt;br /&gt;Threes: 24&lt;br /&gt;Twos: 18&lt;br /&gt;Threes: 27&lt;br /&gt;AlternateIntersect: 18&lt;br /&gt;(etc)&lt;/div&gt; &lt;p&gt;That&amp;#39;s really neat. Quite how often it&amp;#39;ll be useful is a different matter, but I find this kind of thing fascinating to consider. Thanks Frederik!&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1647209" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/Books/default.aspx">Books</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/LINQ/default.aspx">LINQ</category></item><item><title>Mandelbrot revisited - benchmark edition</title><link>http://msmvps.com/blogs/jon_skeet/archive/2008/05/18/mandelbrot-revisited-benchmark-edition.aspx</link><pubDate>Sun, 18 May 2008 21:44:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1624136</guid><dc:creator>skeet</dc:creator><slash:comments>11</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/rsscomments.aspx?PostID=1624136</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/commentapi.aspx?PostID=1624136</wfw:comment><comments>http://msmvps.com/blogs/jon_skeet/archive/2008/05/18/mandelbrot-revisited-benchmark-edition.aspx#comments</comments><description>&lt;p&gt;I&amp;#39;ve had fun with the Mandelbrot set in this blog before, using it as an example of an embarrassingly parallelisable problem and demonstrating Parallel LINQ with it. &lt;/p&gt; &lt;p&gt;This morning, over breakfast, I described the problem to &lt;a href="http://www.brunschen.com/christian/"&gt;Christian Brunschen&lt;/a&gt;, a colleague of mine who has some parallelisation experience through &lt;a href="http://www.brunschen.com/christian/OdinMP/"&gt;implementing OpenMP in a portable manner&lt;/a&gt;. He immediately suggested a few possible changes to the way that I&amp;#39;ve approached things. Given the number of different attempts I&amp;#39;ve now had, I thought it would make sense to write a litte benchmarking app which could easily be expanded as further implementations were considered. The benchmark is &lt;a href="http://pobox.com/%7Eskeet/csharp/blogfiles/MandelbrotBenchmark.zip"&gt;available for download&lt;/a&gt; so you can play around with it yourself. (As is often the case with this kind of thing, it&amp;#39;s not the nicest code in the world for various reasons - the duplication of the sequence generation method, for example... Please don&amp;#39;t use it as a tutorial on actual coding and organisation.)&lt;/p&gt; &lt;h3&gt;Benchmark implementation details&lt;/h3&gt; &lt;p&gt;The benchmark allows you to vary the size of the generated image and the maximum number of iterations per point. The images can be displayed after the test run, but only the time taken to populate a byte array is recorded. The byte arrays are all allocated before any tests are run, and the garbage collector is invoked (as far as it can be) between tests. The images themselves are only generated after the tests have all completed. Each implementation is given a tiny &amp;quot;dummy run&amp;quot; (creating an image 10 pixels across, with a maximum of 2 iterations per point) first to hopefully remove JITting from the benchmarking times. I won&amp;#39;t pretend that this puts everything on a completely level playing field (benchmarking is hard) but hopefully it&amp;#39;s a good start. We check the similarity between the results of each test and the first one - in some cases they could be &amp;quot;nearly all the same&amp;quot; without there being a bug, due to the subtleties of floating point operations and inlining.&lt;/p&gt; &lt;p&gt;The base class that all the generators use takes care of working out the height from the width, remembering the various configuration options, allocating the array, and also providing a simple imperative method to obtain the value of a single point, without using anything fancy. &lt;/p&gt; &lt;p&gt;I originally wanted to put the whole thing in a nice UI, but after wasting nearly an hour trying to get WPF to behave, I decided to go for a simple console app. One day I really must learn how to write GUIs quickly... &lt;/p&gt; &lt;p&gt;Okay, enough introduction - let&amp;#39;s look at the implementations we&amp;#39;re testing, and then the results. The idea is to get a look at how a number of areas influence the results, as well as seeing some nifty ways of expressing things functionally.&lt;/p&gt; &lt;h4&gt;SingleThreadImperativeSimple&lt;/h4&gt; &lt;p&gt;This is the most trivial code you could write, basically. As the base class provides the calculation method, we just go through each row and column, work out the value, and store it in the array. The only attempt at optimisation is keeping the &amp;quot;current index&amp;quot; into the array rather than calculating it for every point.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class="code"&gt;&lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span class="Modifier"&gt;override&lt;/span&gt;&amp;nbsp;&lt;span class="ValueType"&gt;void&lt;/span&gt; Generate()&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="ValueType"&gt;int&lt;/span&gt; index = 0;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;for&lt;/span&gt; (&lt;span class="ValueType"&gt;int&lt;/span&gt; row = 0; row &amp;lt; Height; row++)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;for&lt;/span&gt; (&lt;span class="ValueType"&gt;int&lt;/span&gt; col = 0; col &amp;lt; Width; col++)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Data[index++] = ComputeMandelbrotIndex(row, col);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;} &lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;where &lt;code&gt;ComplexMandelbrotIndex&lt;/code&gt; is in the base class:&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class="code"&gt;&lt;span class="Modifier"&gt;protected&lt;/span&gt;&amp;nbsp;&lt;span class="ValueType"&gt;byte&lt;/span&gt; ComputeMandelbrotIndex(&lt;span class="ValueType"&gt;int&lt;/span&gt; row, &lt;span class="ValueType"&gt;int&lt;/span&gt; col)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="ValueType"&gt;double&lt;/span&gt; x = (col * SampleWidth) / Width + OffsetX;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="ValueType"&gt;double&lt;/span&gt; y = (row * SampleHeight) / Height + OffsetY;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="ValueType"&gt;double&lt;/span&gt; y0 = y;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="ValueType"&gt;double&lt;/span&gt; x0 = x;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;for&lt;/span&gt; (&lt;span class="ValueType"&gt;int&lt;/span&gt; i = 0; i &amp;lt; MaxIterations; i++)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;if&lt;/span&gt; (x * x + y * y &amp;gt;= 4)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;return&lt;/span&gt; (&lt;span class="ValueType"&gt;byte&lt;/span&gt;)((i % 255) + 1);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="ValueType"&gt;double&lt;/span&gt; xtemp = x * x - y * y + x0;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; y = 2 * x * y + y0;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; x = xtemp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;return&lt;/span&gt; 0;&lt;br /&gt;} &lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h4&gt;SingleThreadImperativeInline&lt;/h4&gt; &lt;p&gt;This is largely the same code as SingleThreadImperativeSimple, but with everything inlined. Within the main body, there&amp;#39;s no access to anything other than local variables, and no method calls. One further optimisation is available: points which will have a value of 0 aren&amp;#39;t stored (we assume we&amp;#39;ll always start with a cleared array). &lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class="code"&gt;&lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span class="Modifier"&gt;override&lt;/span&gt;&amp;nbsp;&lt;span class="ValueType"&gt;void&lt;/span&gt; Generate()&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="ValueType"&gt;int&lt;/span&gt; width = Width;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="ValueType"&gt;int&lt;/span&gt; height = Height;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="ValueType"&gt;int&lt;/span&gt; maxIterations = MaxIterations;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="ValueType"&gt;int&lt;/span&gt; index = 0;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="ValueType"&gt;byte&lt;/span&gt;[] data = Data;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;for&lt;/span&gt; (&lt;span class="ValueType"&gt;int&lt;/span&gt; row = 0; row &amp;lt; height; row++)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;for&lt;/span&gt; (&lt;span class="ValueType"&gt;int&lt;/span&gt; col = 0; col &amp;lt; width; col++)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="ValueType"&gt;double&lt;/span&gt; x = (col * SampleWidth) / width + OffsetX;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="ValueType"&gt;double&lt;/span&gt; y = (row * SampleHeight) / height + OffsetY;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="ValueType"&gt;double&lt;/span&gt; y0 = y;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="ValueType"&gt;double&lt;/span&gt; x0 = x;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;for&lt;/span&gt; (&lt;span class="ValueType"&gt;int&lt;/span&gt; i = 0; i &amp;lt; maxIterations; i++)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;if&lt;/span&gt; (x * x + y * y &amp;gt;= 4)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; data[index] = (&lt;span class="ValueType"&gt;byte&lt;/span&gt;)((i % 255) + 1);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;break&lt;/span&gt;;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="ValueType"&gt;double&lt;/span&gt; xtemp = x * x - y * y + x0;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; y = 2 * x * y + y0;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; x = xtemp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="InlineComment"&gt;// Leave data[index] = 0 by default&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; index++;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;} &lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h4&gt;MultiThreadUpFrontSplitImperative&lt;/h4&gt; &lt;p&gt;This should be pretty efficient - work out how many cores we&amp;#39;ve got, split the work equally between them (as chunks of rows, which helps in terms of locality and just incrementing an index in the byte array each time), and then run. Wait until all the threads have finished, and we&amp;#39;re done. Shouldn&amp;#39;t be a lot of context switching required normally, and no synchronization is required. However, if some cores are busy with another process, we&amp;#39;ll end up context switching for no gain. &lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class="code"&gt;&lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span class="Modifier"&gt;override&lt;/span&gt;&amp;nbsp;&lt;span class="ValueType"&gt;void&lt;/span&gt; Generate()&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="ValueType"&gt;int&lt;/span&gt; cores = Environment.ProcessorCount;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="ValueType"&gt;int&lt;/span&gt; rowsPerCore = Height / cores;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; List&amp;lt;Thread&amp;gt; threads = &lt;span class="Keyword"&gt;new&lt;/span&gt; List&amp;lt;Thread&amp;gt;();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;for&lt;/span&gt; (&lt;span class="ValueType"&gt;int&lt;/span&gt; i = 0; i &amp;lt; cores; i++)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="ValueType"&gt;int&lt;/span&gt; firstRow = rowsPerCore * i;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="ValueType"&gt;int&lt;/span&gt; rowsToCompute = rowsPerCore;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;if&lt;/span&gt; (i == cores - 1)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; rowsToCompute = Height-(rowsPerCore*(cores-1));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Thread thread = &lt;span class="Keyword"&gt;new&lt;/span&gt; Thread(() =&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="ValueType"&gt;int&lt;/span&gt; index = firstRow * Width;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;for&lt;/span&gt; (&lt;span class="ValueType"&gt;int&lt;/span&gt; row = firstRow; row &amp;lt; firstRow + rowsToCompute; row++)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;for&lt;/span&gt; (&lt;span class="ValueType"&gt;int&lt;/span&gt; col = 0; col &amp;lt; Width; col++)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Data[index++] = ComputeMandelbrotIndex(row, col);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; });&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; thread.Start();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; threads.Add(thread);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; threads.ForEach(thread =&amp;gt; thread.Join());&lt;br /&gt;} &lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h4&gt;MultiThreadRowFetching&lt;/h4&gt; &lt;p&gt;Again, we use a fixed number of threads - but this time we start off with a queue of work - one task per row. The queue has to be synchronized every time we use it, and we also have to check whether or not it&amp;#39;s empty. Plenty of scope for lock contention here, particularly as the number of cores increases. &lt;/p&gt; 
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class="code"&gt;
&lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span class="Modifier"&gt;override&lt;/span&gt;&amp;nbsp;&lt;span class="ValueType"&gt;void&lt;/span&gt;&amp;nbsp;Generate()&lt;br /&gt;
{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Queue&amp;lt;&lt;span class="ValueType"&gt;int&lt;/span&gt;&amp;gt;&amp;nbsp;rowsLeft&amp;nbsp;=&amp;nbsp;&lt;span class="Keyword"&gt;new&lt;/span&gt;&amp;nbsp;Queue&amp;lt;&lt;span class="ValueType"&gt;int&lt;/span&gt;&amp;gt;(Enumerable.Range(0,&amp;nbsp;Height));&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;List&amp;lt;Thread&amp;gt;&amp;nbsp;threads&amp;nbsp;=&amp;nbsp;&lt;span class="Keyword"&gt;new&lt;/span&gt;&amp;nbsp;List&amp;lt;Thread&amp;gt;();&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Statement"&gt;for&lt;/span&gt;&amp;nbsp;(&lt;span class="ValueType"&gt;int&lt;/span&gt;&amp;nbsp;i&amp;nbsp;=&amp;nbsp;0;&amp;nbsp;i&amp;nbsp;&amp;lt;&amp;nbsp;Environment.ProcessorCount;&amp;nbsp;i++)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Thread&amp;nbsp;thread&amp;nbsp;=&amp;nbsp;&lt;span class="Keyword"&gt;new&lt;/span&gt;&amp;nbsp;Thread(()&amp;nbsp;=&amp;gt;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Statement"&gt;while&lt;/span&gt;&amp;nbsp;(&lt;span class="Keyword"&gt;true&lt;/span&gt;)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="ValueType"&gt;int&lt;/span&gt;&amp;nbsp;row;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Statement"&gt;lock&lt;/span&gt;&amp;nbsp;(rowsLeft)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Statement"&gt;if&lt;/span&gt;&amp;nbsp;(rowsLeft.Count&amp;nbsp;==&amp;nbsp;0)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Statement"&gt;break&lt;/span&gt;;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;row&amp;nbsp;=&amp;nbsp;rowsLeft.Dequeue();&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="ValueType"&gt;int&lt;/span&gt;&amp;nbsp;index&amp;nbsp;=&amp;nbsp;row&amp;nbsp;*&amp;nbsp;Width;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Statement"&gt;for&lt;/span&gt;&amp;nbsp;(&lt;span class="ValueType"&gt;int&lt;/span&gt;&amp;nbsp;col&amp;nbsp;=&amp;nbsp;0;&amp;nbsp;col&amp;nbsp;&amp;lt;&amp;nbsp;Width;&amp;nbsp;col++)&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Data[index++]&amp;nbsp;=&amp;nbsp;ComputeMandelbrotIndex(row,&amp;nbsp;col);&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;});&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;thread.Start();&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;threads.Add(thread);&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;threads.ForEach(thread&amp;nbsp;=&amp;gt;&amp;nbsp;thread.Join());&lt;br /&gt;
}
&lt;/div&gt;

&lt;h4&gt;SingleThreadLinqSimple&lt;/h4&gt; &lt;p&gt;This is the &lt;a href="http://msmvps.com/blogs/jon.skeet/archive/2007/10/03/linq-to-silliness-generating-a-mandelbrot-with-parallel-potential.aspx"&gt;first version&lt;/a&gt; of Mandelbrot generation I wrote since thinking of using LINQ, tweaked a litte to dump the output into an existing array instead of creating a new one. It&amp;#39;s essentially the same as SingleThreadImperativeSimple but with the &lt;code&gt;for&lt;/code&gt; loops replaced with a query expression. &lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class="code"&gt;&lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span class="Modifier"&gt;override&lt;/span&gt;&amp;nbsp;&lt;span class="ValueType"&gt;void&lt;/span&gt; Generate()&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;var&lt;/span&gt; query = &lt;span class="Linq"&gt;from&lt;/span&gt; row &lt;span class="Statement"&gt;in&lt;/span&gt; Enumerable.Range(0, Height)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;from&lt;/span&gt; col &lt;span class="Statement"&gt;in&lt;/span&gt; Enumerable.Range(0, Width)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;select&lt;/span&gt; ComputeMandelbrotIndex(row, col);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="ValueType"&gt;int&lt;/span&gt; index=0;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;foreach&lt;/span&gt; (&lt;span class="ValueType"&gt;byte&lt;/span&gt; b &lt;span class="Statement"&gt;in&lt;/span&gt; query)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Data[index++] = b;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;} &lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h4&gt;ParallelLinqRowByRowWithCopy&lt;/h4&gt; &lt;p&gt;My first attempt using Parallel LINQ was &lt;a href="http://msmvps.com/blogs/jon.skeet/archive/2007/12/04/a-cautionary-parallel-tale-ordering-isn-t-simple.aspx"&gt;somewhat disastrous&lt;/a&gt; due to the nature of PLINQ&amp;#39;s ordering. To combat this effect, I initially computed a row at a time, then copying each row into place afterwards: &lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class="code"&gt;&lt;span class="Modifier"&gt;private&lt;/span&gt;&amp;nbsp;&lt;span class="ValueType"&gt;byte&lt;/span&gt;[] ComputeMandelbrotRow(&lt;span class="ValueType"&gt;int&lt;/span&gt; row)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="ValueType"&gt;byte&lt;/span&gt;[] ret = &lt;span class="Keyword"&gt;new&lt;/span&gt;&amp;nbsp;&lt;span class="ValueType"&gt;byte&lt;/span&gt;[Width];&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;for&lt;/span&gt; (&lt;span class="ValueType"&gt;int&lt;/span&gt; col = 0; col &amp;lt; Width; col++)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ret[col] = ComputeMandelbrotIndex(row, col);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;return&lt;/span&gt; ret;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span class="Modifier"&gt;override&lt;/span&gt;&amp;nbsp;&lt;span class="ValueType"&gt;void&lt;/span&gt; Generate()&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;var&lt;/span&gt; query = &lt;span class="Linq"&gt;from&lt;/span&gt; row &lt;span class="Statement"&gt;in&lt;/span&gt; Enumerable.Range(0, Height).AsParallel(ParallelQueryOptions.PreserveOrdering)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;select&lt;/span&gt; ComputeMandelbrotRow(row);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="ValueType"&gt;int&lt;/span&gt; rowStart = 0;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;foreach&lt;/span&gt; (&lt;span class="ValueType"&gt;byte&lt;/span&gt;[] row &lt;span class="Statement"&gt;in&lt;/span&gt; query)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Array.Copy(row, 0, Data, rowStart, Width);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; rowStart += Width;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;} &lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h4&gt;ParallelLinqRowByRowInPlace&lt;/h4&gt; &lt;p&gt;An obvious potential improvement is to write the data to the eventual target array as we go, to avoid creating the extra array creation and copying. At this point we have less of a purely functional solution, but it&amp;#39;s interesting anyway. Note that to use this idea in a query expression we have to return &lt;i&gt;something&lt;/i&gt; even though it&amp;#39;s not useful. Likewise we have to make the query execute fully - so I use &lt;code&gt;Max()&lt;/code&gt; to ensure that all the results will be computed. (I originally tried &lt;code&gt;Count()&lt;/code&gt; but that didn&amp;#39;t work - presumably because the count of the results is known before the actual values are.) As we&amp;#39;re writing the data to the right place on each iteration, we no longer need to preserve ordering. &lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class="code"&gt;&lt;span class="Modifier"&gt;private&lt;/span&gt;&amp;nbsp;&lt;span class="ValueType"&gt;int&lt;/span&gt; ComputeMandelbrotRow(&lt;span class="ValueType"&gt;int&lt;/span&gt; row)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="ValueType"&gt;int&lt;/span&gt; index = row * Width;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;for&lt;/span&gt; (&lt;span class="ValueType"&gt;int&lt;/span&gt; col = 0; col &amp;lt; Width; col++)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Data[index++] = ComputeMandelbrotIndex(row, col);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;return&lt;/span&gt; 0;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span class="Modifier"&gt;override&lt;/span&gt;&amp;nbsp;&lt;span class="ValueType"&gt;void&lt;/span&gt; Generate()&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;var&lt;/span&gt; query = &lt;span class="Linq"&gt;from&lt;/span&gt; row &lt;span class="Statement"&gt;in&lt;/span&gt; Enumerable.Range(0, Height).AsParallel()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;select&lt;/span&gt; ComputeMandelbrotRow(row);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; query.Max();&lt;br /&gt;} &lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h4&gt;ParallelLinqWithSequenceOfPoints&lt;/h4&gt; &lt;p&gt;After this initial foray into Parallel LINQ, Nicholas Palladinos suggested that I could adapt the original idea in a more elegant manner by treating the sequence of points as a single input sequence, and asking Parallel LINQ to preserve the order of that whole sequence. &lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class="code"&gt;&lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span class="Modifier"&gt;override&lt;/span&gt;&amp;nbsp;&lt;span class="ValueType"&gt;void&lt;/span&gt; Generate()&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;var&lt;/span&gt; points = &lt;span class="Linq"&gt;from&lt;/span&gt; row &lt;span class="Statement"&gt;in&lt;/span&gt; Enumerable.Range(0, Height)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;from&lt;/span&gt; col &lt;span class="Statement"&gt;in&lt;/span&gt; Enumerable.Range(0, Width)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;select&lt;/span&gt;&amp;nbsp;&lt;span class="Keyword"&gt;new&lt;/span&gt; { row, col };&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;var&lt;/span&gt; query = &lt;span class="Linq"&gt;from&lt;/span&gt; point &lt;span class="Statement"&gt;in&lt;/span&gt; points.AsParallel(ParallelQueryOptions.PreserveOrdering)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;select&lt;/span&gt; ComputeMandelbrotIndex(point.row, point.col);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="ValueType"&gt;int&lt;/span&gt; index=0;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;foreach&lt;/span&gt; (&lt;span class="ValueType"&gt;byte&lt;/span&gt; b &lt;span class="Statement"&gt;in&lt;/span&gt; query)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Data[index++] = b;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;} &lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h4&gt;SingleThreadLinqWithGenerator&lt;/h4&gt; &lt;p&gt;My next step was to try to put the &lt;a href="http://msmvps.com/blogs/jon.skeet/archive/2007/10/03/linq-to-silliness-generating-a-mandelbrot-with-parallel-potential.aspx"&gt;whole guts of the algorithm into the query expression&lt;/a&gt;, using a &lt;code&gt;Complex&lt;/code&gt; value type and a generator to create a sequence of complex numbers generated from the starting point. This is quite a natural step, as the value is computed by just considering this infinite sequence and seeing how quickly it escapes from the circle of radius 2 on the complex plane. Aside from anything else, I think it&amp;#39;s a nice example of deferred execution and streaming - the sequence really would go on forever if we didn&amp;#39;t limit it with the &lt;code&gt;Take&lt;/code&gt; and &lt;code&gt;TakeWhile&lt;/code&gt; calls, but the generator itself doesn&amp;#39;t know it&amp;#39;s being limited. This version uses a sequence of points as per ParallelLinqWithSequenceOfPoints to make it easier to parallelise later. &lt;/p&gt; &lt;p&gt;It&amp;#39;s not exactly an efficient way of doing things though - there&amp;#39;s a huge amount of calling going on from one iterator to another. I&amp;#39;m actually quite surprised that the final results aren&amp;#39;t worse than they are. &lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class="code"&gt;&lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span class="Modifier"&gt;override&lt;/span&gt;&amp;nbsp;&lt;span class="ValueType"&gt;void&lt;/span&gt; Generate()&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;var&lt;/span&gt; points = &lt;span class="Linq"&gt;from&lt;/span&gt; row &lt;span class="Statement"&gt;in&lt;/span&gt; Enumerable.Range(0, Height)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;from&lt;/span&gt; col &lt;span class="Statement"&gt;in&lt;/span&gt; Enumerable.Range(0, Width)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;select&lt;/span&gt;&amp;nbsp;&lt;span class="Keyword"&gt;new&lt;/span&gt; { row, col };&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;var&lt;/span&gt; query = &lt;span class="Linq"&gt;from&lt;/span&gt; point &lt;span class="Statement"&gt;in&lt;/span&gt; points&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="InlineComment"&gt;// Work out the initial complex value from the row and column&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;let&lt;/span&gt; c = &lt;span class="Keyword"&gt;new&lt;/span&gt; Complex((point.col * SampleWidth) / Width + OffsetX,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; (point.row * SampleHeight) / Height + OffsetY)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="InlineComment"&gt;// Work out the number of iterations&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;select&lt;/span&gt; GenerateSequence(c, x =&amp;gt; x * x + c).TakeWhile(x =&amp;gt; x.SquareLength &amp;lt; 4)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; .Take(MaxIterations)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; .Count() &lt;span class="Linq"&gt;into&lt;/span&gt; count&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="InlineComment"&gt;// Map that to an appropriate byte value&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;select&lt;/span&gt; (&lt;span class="ValueType"&gt;byte&lt;/span&gt;)(count == MaxIterations ? 0 : (count % 255) + 1);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="ValueType"&gt;int&lt;/span&gt; index = 0;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;foreach&lt;/span&gt; (&lt;span class="ValueType"&gt;byte&lt;/span&gt; b &lt;span class="Statement"&gt;in&lt;/span&gt; query)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Data[index++] = b;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span class="Modifier"&gt;static&lt;/span&gt; IEnumerable&amp;lt;T&amp;gt; GenerateSequence&amp;lt;T&amp;gt;(T start, Func&amp;lt;T, T&amp;gt; step)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; T value = start;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;while&lt;/span&gt; (&lt;span class="Keyword"&gt;true&lt;/span&gt;)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;yield&lt;/span&gt;&amp;nbsp;&lt;span class="Statement"&gt;return&lt;/span&gt; value;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; value = step(value);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;} &lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h4&gt;ParallelLinqWithGenerator&lt;/h4&gt; &lt;p&gt;From the previous implementation, parallelisation is simple. &lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class="code"&gt;&lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span class="Modifier"&gt;override&lt;/span&gt;&amp;nbsp;&lt;span class="ValueType"&gt;void&lt;/span&gt; Generate()&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;var&lt;/span&gt; points = &lt;span class="Linq"&gt;from&lt;/span&gt; row &lt;span class="Statement"&gt;in&lt;/span&gt; Enumerable.Range(0, Height)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;from&lt;/span&gt; col &lt;span class="Statement"&gt;in&lt;/span&gt; Enumerable.Range(0, Width)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;select&lt;/span&gt;&amp;nbsp;&lt;span class="Keyword"&gt;new&lt;/span&gt; { row, col };&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;var&lt;/span&gt; query = &lt;span class="Linq"&gt;from&lt;/span&gt; point &lt;span class="Statement"&gt;in&lt;/span&gt; points.AsParallel(ParallelQueryOptions.PreserveOrdering)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="InlineComment"&gt;// Work out the initial complex value from the row and column&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;let&lt;/span&gt; c = &lt;span class="Keyword"&gt;new&lt;/span&gt; Complex((point.col * SampleWidth) / Width + OffsetX,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; (point.row * SampleHeight) / Height + OffsetY)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="InlineComment"&gt;// Work out the number of iterations&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;select&lt;/span&gt; GenerateSequence(c, x =&amp;gt; x * x + c).TakeWhile(x =&amp;gt; x.SquareLength &amp;lt; 4)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; .Take(MaxIterations)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; .Count() &lt;span class="Linq"&gt;into&lt;/span&gt; count&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="InlineComment"&gt;// Map that to an appropriate byte value&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;select&lt;/span&gt; (&lt;span class="ValueType"&gt;byte&lt;/span&gt;)(count == MaxIterations ? 0 : (count % 255) + 1);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="ValueType"&gt;int&lt;/span&gt; index = 0;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;foreach&lt;/span&gt; (&lt;span class="ValueType"&gt;byte&lt;/span&gt; b &lt;span class="Statement"&gt;in&lt;/span&gt; query)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Data[index++] = b;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;} &lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h4&gt;SingleThreadImperativeWithComplex&lt;/h4&gt; &lt;p&gt;Having already seen how slow the generator version was in the past, I thought it would be worth checking whether or not this was due to the use of the &lt;code&gt;Complex&lt;/code&gt; struct - so this is a version which uses that, but is otherwise just like the very first implementation (SingleThreadImperativeSimple).&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class="code"&gt;&lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span class="Modifier"&gt;override&lt;/span&gt;&amp;nbsp;&lt;span class="ValueType"&gt;void&lt;/span&gt; Generate()&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="ValueType"&gt;int&lt;/span&gt; index = 0;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;for&lt;/span&gt; (&lt;span class="ValueType"&gt;int&lt;/span&gt; row = 0; row &amp;lt; Height; row++)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;for&lt;/span&gt; (&lt;span class="ValueType"&gt;int&lt;/span&gt; col = 0; col &amp;lt; Width; col++)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Data[index++] = ComputeMandelbrotIndexWithComplex(row, col);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="ValueType"&gt;byte&lt;/span&gt; ComputeMandelbrotIndexWithComplex(&lt;span class="ValueType"&gt;int&lt;/span&gt; row, &lt;span class="ValueType"&gt;int&lt;/span&gt; col)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="ValueType"&gt;double&lt;/span&gt; x = (col * SampleWidth) / Width + OffsetX;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="ValueType"&gt;double&lt;/span&gt; y = (row * SampleHeight) / Height + OffsetY;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Complex start = &lt;span class="Keyword"&gt;new&lt;/span&gt; Complex(x, y);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Complex current = start;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;for&lt;/span&gt; (&lt;span class="ValueType"&gt;int&lt;/span&gt; i = 0; i &amp;lt; MaxIterations; i++)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;if&lt;/span&gt; (current.SquareLength &amp;gt;= 4)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;return&lt;/span&gt; (&lt;span class="ValueType"&gt;byte&lt;/span&gt;)((i % 255) + 1);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; current = current * current + start;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;return&lt;/span&gt; 0;&lt;br /&gt;} &lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h4&gt;UnorderedParallelLinqSimple&lt;/h4&gt; &lt;p&gt;This is where my colleague, Christian, came in. He suggested that instead of ordering the results, we just return the point as well as its value. We can then populate the array directly, regardless of the order of the results. The first version just uses an anonymous type to represent the combination:&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class="code"&gt;&lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span class="Modifier"&gt;override&lt;/span&gt;&amp;nbsp;&lt;span class="ValueType"&gt;void&lt;/span&gt; Generate()&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;var&lt;/span&gt; query = &lt;span class="Linq"&gt;from&lt;/span&gt; row &lt;span class="Statement"&gt;in&lt;/span&gt; Enumerable.Range(0, Height).AsParallel()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;from&lt;/span&gt; col &lt;span class="Statement"&gt;in&lt;/span&gt; Enumerable.Range(0, Width)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;select&lt;/span&gt;&amp;nbsp;&lt;span class="Keyword"&gt;new&lt;/span&gt; { row, col, value = ComputeMandelbrotIndex(row, col) };&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;foreach&lt;/span&gt; (&lt;span class="Linq"&gt;var&lt;/span&gt; x &lt;span class="Statement"&gt;in&lt;/span&gt; query)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Data[x.row * Width + x.col] = x.value;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;} &lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h4&gt;UnorderedParallelLinqWithStruct&lt;/h4&gt; &lt;p&gt;Creating a new garbage-collected object on the heap for each point isn&amp;#39;t the world&amp;#39;s greatest idea. A very simple transformation is to use a struct instead. Without knowing the PLINQ implementation, it seems likely that the values will still end up on the heap somehow (how else could they be communicated between threads?) but I&amp;#39;d still expect a certain saving from this simple step. &lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class="code"&gt;&lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span class="Modifier"&gt;override&lt;/span&gt;&amp;nbsp;&lt;span class="ValueType"&gt;void&lt;/span&gt; Generate()&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;var&lt;/span&gt; query = &lt;span class="Linq"&gt;from&lt;/span&gt; row &lt;span class="Statement"&gt;in&lt;/span&gt; Enumerable.Range(0, Height).AsParallel()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;from&lt;/span&gt; col &lt;span class="Statement"&gt;in&lt;/span&gt; Enumerable.Range(0, Width)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;select&lt;/span&gt;&amp;nbsp;&lt;span class="Keyword"&gt;new&lt;/span&gt; Result (row, col, ComputeMandelbrotIndex(row, col));&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;foreach&lt;/span&gt; (&lt;span class="Linq"&gt;var&lt;/span&gt; x &lt;span class="Statement"&gt;in&lt;/span&gt; query)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Data[x.Row * Width + x.Column] = x.Value;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="ValueType"&gt;struct&lt;/span&gt; Result&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Modifier"&gt;internal&lt;/span&gt;&amp;nbsp;&lt;span class="ValueType"&gt;int&lt;/span&gt; row, col;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Modifier"&gt;internal&lt;/span&gt;&amp;nbsp;&lt;span class="ValueType"&gt;byte&lt;/span&gt; value;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Modifier"&gt;internal&lt;/span&gt;&amp;nbsp;&lt;span class="ValueType"&gt;int&lt;/span&gt; Row { get { &lt;span class="Statement"&gt;return&lt;/span&gt; row; } }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Modifier"&gt;internal&lt;/span&gt;&amp;nbsp;&lt;span class="ValueType"&gt;int&lt;/span&gt; Column { get { &lt;span class="Statement"&gt;return&lt;/span&gt; col; } }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Modifier"&gt;internal&lt;/span&gt;&amp;nbsp;&lt;span class="ValueType"&gt;byte&lt;/span&gt; Value { get { &lt;span class="Statement"&gt;return&lt;/span&gt; value; } }&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Modifier"&gt;internal&lt;/span&gt; Result(&lt;span class="ValueType"&gt;int&lt;/span&gt; row, &lt;span class="ValueType"&gt;int&lt;/span&gt; col, &lt;span class="ValueType"&gt;byte&lt;/span&gt; value)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Keyword"&gt;this&lt;/span&gt;.row = row;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Keyword"&gt;this&lt;/span&gt;.col = col;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Keyword"&gt;this&lt;/span&gt;.value = value;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;} &lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h4&gt;UnorderedParallelLinqInPlace&lt;/h4&gt; &lt;p&gt;Why bother returning the data at all? We can just write the data in place, like we did earlier with ParallelLinqRowByRowInPlace but in a more aggressive fashion (and the disadvantage of computing the index for each point). Again, we have to return a dummy value and iterate through those dummy results to force all the computations to go through. &lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class="code"&gt;&lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span class="Modifier"&gt;override&lt;/span&gt;&amp;nbsp;&lt;span class="ValueType"&gt;void&lt;/span&gt; Generate()&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;var&lt;/span&gt; query = &lt;span class="Linq"&gt;from&lt;/span&gt; row &lt;span class="Statement"&gt;in&lt;/span&gt; Enumerable.Range(0, Height).AsParallel()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;from&lt;/span&gt; col &lt;span class="Statement"&gt;in&lt;/span&gt; Enumerable.Range(0, Width)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="InlineComment"&gt;// Note side-effect!&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;select&lt;/span&gt; Data[row*Width + col] = ComputeMandelbrotIndex(row, col);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="InlineComment"&gt;// Force iteration through all results&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; query.Max();&lt;br /&gt;} &lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h4&gt;UnorderedParallelLinqInPlaceWithDelegate&lt;/h4&gt; &lt;p&gt;UnorderedParallelLinqInPlace feels slightly nasty - we&amp;#39;ve clearly got a side-effect within the loop, it&amp;#39;s just that we know the side-effects are all orthogonal. We can make ourselves feel slightly cleaner by separating the side-effect from the main algorithm, by way of a delegate. The loop can hold its hands up and say, &amp;quot;I&amp;#39;m side-effect free if you are.&amp;quot; It&amp;#39;s not hugely satisfactory, but it&amp;#39;ll be interesting to see the penalty we pay for this attempt to be purer. &lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class="code"&gt;IEnumerable&amp;lt;T&amp;gt; Generate&amp;lt;T&amp;gt;(Func&amp;lt;&lt;span class="ValueType"&gt;int&lt;/span&gt;, &lt;span class="ValueType"&gt;int&lt;/span&gt;, T&amp;gt; transformation)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;var&lt;/span&gt; query = &lt;span class="Linq"&gt;from&lt;/span&gt; row &lt;span class="Statement"&gt;in&lt;/span&gt; Enumerable.Range(0, Height).AsParallel()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;from&lt;/span&gt; col &lt;span class="Statement"&gt;in&lt;/span&gt; Enumerable.Range(0, Width)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="InlineComment"&gt;// Side-effect only if transformation contains one...&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;select&lt;/span&gt; transformation(row, col);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;return&lt;/span&gt; query;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span class="Modifier"&gt;override&lt;/span&gt;&amp;nbsp;&lt;span class="ValueType"&gt;void&lt;/span&gt; Generate()&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="InlineComment"&gt;// Transformation with side-effect&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Func&amp;lt;&lt;span class="ValueType"&gt;int&lt;/span&gt;,&lt;span class="ValueType"&gt;int&lt;/span&gt;,&lt;span class="ValueType"&gt;byte&lt;/span&gt;&amp;gt; transformation = (row, col) =&amp;gt; Data[row * Width + col] = ComputeMandelbrotIndex(row, col);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Generate(transformation).Max();&lt;br /&gt;} &lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h4&gt;UnorderedParallelLinqInPlaceWithGenerator&lt;/h4&gt; &lt;p&gt;We can easily combine the earlier generator code with any of these new ways of processing the results. Here we use our &amp;quot;algorithm in the query&amp;quot; approach but process the results as we go to avoid ordering issues. &lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class="code"&gt;&lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span class="Modifier"&gt;override&lt;/span&gt;&amp;nbsp;&lt;span class="ValueType"&gt;void&lt;/span&gt; Generate()&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;var&lt;/span&gt; query = &lt;span class="Linq"&gt;from&lt;/span&gt; row &lt;span class="Statement"&gt;in&lt;/span&gt; Enumerable.Range(0, Height).AsParallel()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;from&lt;/span&gt; col &lt;span class="Statement"&gt;in&lt;/span&gt; Enumerable.Range(0, Width)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="InlineComment"&gt;// Work out the initial complex value from the row and column&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;let&lt;/span&gt; c = &lt;span class="Keyword"&gt;new&lt;/span&gt; Complex((col * SampleWidth) / Width + OffsetX,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; (row * SampleHeight) / Height + OffsetY)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="InlineComment"&gt;// Work out the number of iterations&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;let&lt;/span&gt; count = GenerateSequence(c, x =&amp;gt; x * x + c).TakeWhile(x =&amp;gt; x.SquareLength &amp;lt; 4)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; .Take(MaxIterations)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; .Count()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="InlineComment"&gt;// Map that to an appropriate byte value - and write it in place&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;select&lt;/span&gt; Data[row * Width + col]&amp;nbsp; = (&lt;span class="ValueType"&gt;byte&lt;/span&gt;)(count == MaxIterations ? 0 : (count % 255) + 1);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="InlineComment"&gt;// Force execution&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; query.Max();&lt;br /&gt;} &lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h4&gt;ParallelForLoop&lt;/h4&gt; &lt;p&gt;The Parallel Extensions library doesn&amp;#39;t just contain Parallel LINQ. It also has various other building blocks for parallelism, including a parallel for loop. This allows very simple parallelism of our very first generator - we just turn the outside loop into a parallel for loop, turning the previous inner loop into a delegate. We need to move the index variable into the outer loop so there&amp;#39;ll be one per row (otherwise they&amp;#39;d trample on each other) but that&amp;#39;s about it: &lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class="code"&gt;&lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span class="Modifier"&gt;override&lt;/span&gt;&amp;nbsp;&lt;span class="ValueType"&gt;void&lt;/span&gt; Generate()&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Parallel.For(0, Height, row =&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="ValueType"&gt;int&lt;/span&gt; index = row * Width;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;for&lt;/span&gt; (&lt;span class="ValueType"&gt;int&lt;/span&gt; col = 0; col &amp;lt; Width; col++)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Data[index++] = ComputeMandelbrotIndex(row, col);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; });&lt;br /&gt;} &lt;/div&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;h3&gt;Results&lt;/h3&gt; &lt;p&gt;A benchmark is nothing without results, so here they are on my dual core laptop, from three test runs. The first is the &amp;quot;default&amp;quot; settings I used to develop the benchmark - nothing hugely strenuous, but enough to see differences. I then tried a larger image with the same maximum number of iterations, then the original size with a larger number of iterations. The results are in alphabetical order because that&amp;#39;s how the test prints them :) Times are in milliseconds.&lt;/p&gt; &lt;table cellpadding="2" cellspacing="0"&gt;  &lt;tr&gt; &lt;th&gt;Implementation&lt;/th&gt; &lt;th&gt;Width=1200; MaxIterations=200&lt;/th&gt; &lt;th&gt;Width=3000; MaxIterations=200&lt;/th&gt; &lt;th&gt;Width=1200; MaxIterations=800&lt;/th&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;MultiThreadRowFetching&lt;/td&gt; &lt;td&gt;380&lt;/td&gt; &lt;td&gt;2479&lt;/td&gt; &lt;td&gt;1311&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;MultiThreadUpFrontSplitImperative&lt;/td&gt; &lt;td&gt;384&lt;/td&gt; &lt;td&gt;2545&lt;/td&gt; &lt;td&gt;2088&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;ParallelForLoop&lt;/td&gt; &lt;td&gt;376&lt;/td&gt; &lt;td&gt;2361&lt;/td&gt; &lt;td&gt;1292&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;ParallelLinqRowByRowInPlace&lt;/td&gt; &lt;td&gt;378&lt;/td&gt; &lt;td&gt;2347&lt;/td&gt; &lt;td&gt;1295&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;ParallelLinqRowByRowWithCopy&lt;/td&gt; &lt;td&gt;382&lt;/td&gt; &lt;td&gt;2376&lt;/td&gt; &lt;td&gt;1288&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;ParallelLinqWithGenerator&lt;/td&gt; &lt;td&gt;4782&lt;/td&gt; &lt;td&gt;29752&lt;/td&gt; &lt;td&gt;16626&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;ParallelLinqWithSequenceOfPoints&lt;/td&gt; &lt;td&gt;549&lt;/td&gt; &lt;td&gt;3413&lt;/td&gt; &lt;td&gt;1462&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;SingleThreadImperativeInline&lt;/td&gt; &lt;td&gt;684&lt;/td&gt; &lt;td&gt;4352&lt;/td&gt; &lt;td&gt;2455&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;SingleThreadImperativeSimple&lt;/td&gt; &lt;td&gt;704&lt;/td&gt; &lt;td&gt;4353&lt;/td&gt; &lt;td&gt;2372&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;SingleThreadImperativeWithComplex&lt;/td&gt; &lt;td&gt;2795&lt;/td&gt; &lt;td&gt;16720&lt;/td&gt; &lt;td&gt;9800&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;SingleThreadLinqSimple&lt;/td&gt; &lt;td&gt;726&lt;/td&gt; &lt;td&gt;4522&lt;/td&gt; &lt;td&gt;2438&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;SingleThreadLinqWithGenerator&lt;/td&gt; &lt;td&gt;8902&lt;/td&gt; &lt;td&gt;52586&lt;/td&gt; &lt;td&gt;30075&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;UnorderedParalleLinqInPlace&lt;/td&gt; &lt;td&gt;422&lt;/td&gt; &lt;td&gt;2586&lt;/td&gt; &lt;td&gt;1317&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;UnorderedParallelLinqInPlaceWithDelegate&lt;/td&gt; &lt;td&gt;509&lt;/td&gt; &lt;td&gt;3093&lt;/td&gt; &lt;td&gt;1392&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;UnorderedParallelLinqInPlaceWithGenerator&lt;/td&gt; &lt;td&gt;5046&lt;/td&gt; &lt;td&gt;31657&lt;/td&gt; &lt;td&gt;17026&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;UnorderedParallelLinqSimple&lt;/td&gt; &lt;td&gt;556&lt;/td&gt; &lt;td&gt;3449&lt;/td&gt; &lt;td&gt;1448&lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td&gt;UnorderedParalelLinqWithStruct&lt;/td&gt; &lt;td&gt;511&lt;/td&gt; &lt;td&gt;3227&lt;/td&gt; &lt;td&gt;1427&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt; &lt;h3&gt;Conclusions&lt;/h3&gt; &lt;p&gt;So, what have we learned? Well... bearing in mind that benchmarks like this are often misleading compared with real applications, etc it&amp;#39;s still interesting that:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Parallel Extensions rocks. If I were trying to include a Mandelbrot generation implementation in a production setting, I&amp;#39;d definitely go for the parallel for loop - it&amp;#39;s simple, but works just as well as anything else.&lt;/li&gt; &lt;li&gt;The micro-optimisation of SingleThreadImperativeInline really doesn&amp;#39;t help much, but makes the code harder to understand - just like so many micro-optimisations.&lt;/li&gt; &lt;li&gt;The &amp;quot;generator&amp;quot; form of LINQ really doesn&amp;#39;t perform well at all. It does parallelise pretty well, as you&amp;#39;d expect, but it&amp;#39;s just plain slow.&lt;/li&gt; &lt;li&gt;Part of the slowness is almost certainly due to the use of the &lt;code&gt;Complex&lt;/code&gt; struct, given the results of SingleThreadImperativeWithComplex. Not sure what&amp;#39;s going on there.&lt;/li&gt; &lt;li&gt;The extra abstraction step from UnorderedParallelLinqInPlace to UnorderedParallelLinqInPlaceWithDelegate does have a significant impact, at least when the maximum number of iterations per point isn&amp;#39;t the dominant force. That doesn&amp;#39;t mean it would be a bad idea in production, of course - just somewhere to consider when running against performance issues.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;I suspect I&amp;#39;ve missed some notable points though - comments?&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1624136" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/Wacky+Ideas/default.aspx">Wacky Ideas</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/LINQ/default.aspx">LINQ</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/Parallelisation/default.aspx">Parallelisation</category></item><item><title>Odd query expressions</title><link>http://msmvps.com/blogs/jon_skeet/archive/2008/02/29/odd-query-expressions.aspx</link><pubDate>Fri, 29 Feb 2008 12:36:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1528207</guid><dc:creator>skeet</dc:creator><slash:comments>4</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/rsscomments.aspx?PostID=1528207</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/commentapi.aspx?PostID=1528207</wfw:comment><comments>http://msmvps.com/blogs/jon_skeet/archive/2008/02/29/odd-query-expressions.aspx#comments</comments><description>&lt;p&gt;Yesterday, I was proof reading chapter 11 of the book (and chapter 12, and chapter 13 - it was a long night). Reading my own text about how query expressions work led me to wonder just how far I could push the compiler in terms of understanding completely bizarre query expressions.&lt;/p&gt; &lt;h3&gt;Background&lt;/h3&gt; &lt;p&gt;Query expressions in C# 3 work by translating them into &amp;quot;normal&amp;quot; C# first, then applying normal compilation. So, for instance, a query expression of:&lt;/p&gt; &lt;p&gt;&lt;div class="code"&gt; &lt;span class="Linq"&gt;from&lt;/span&gt;&amp;nbsp;x&amp;nbsp;&lt;span class="Statement"&gt;in&lt;/span&gt;&amp;nbsp;words&lt;br /&gt; &lt;span class="Linq"&gt;where&lt;/span&gt;&amp;nbsp;x.Length&amp;nbsp;&amp;gt;&amp;nbsp;5&lt;br /&gt; &lt;span class="Linq"&gt;select&lt;/span&gt;&amp;nbsp;x.ToUpper() &lt;/div&gt;&lt;/p&gt; &lt;p&gt;... is translated into this:&lt;/p&gt; &lt;p&gt;&lt;div class="code"&gt; words.Where(x&amp;nbsp;=&amp;gt;&amp;nbsp;x.Length&amp;nbsp;&amp;gt;&amp;nbsp;5)&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;.Select(x&amp;nbsp;=&amp;gt;&amp;nbsp;x.ToUpper()) &lt;/div&gt;&lt;/p&gt; &lt;p&gt;Now, usually the source expression (&lt;code&gt;words&lt;/code&gt; in this case) is something like a variable, or the result of a method or property call. However, the spec doesn&amp;#39;t say it has to be... let&amp;#39;s see what else we could do. We&amp;#39;ll keep the query expression as simple as possible - just &lt;code&gt;from x in source select x&lt;/code&gt;.&lt;/p&gt; &lt;h3&gt;Types&lt;/h3&gt; &lt;p&gt;What if the source expression is a type? The query expression would then compile to &lt;code&gt;TypeName.Select(x =&amp;gt; x)&lt;/code&gt; which of course works if there&amp;#39;s a static &lt;code&gt;Select&lt;/code&gt; method taking an appropriate delegate or expression tree. And indeed it works:&lt;/p&gt; &lt;p&gt;&lt;div class="code"&gt; &lt;span class="Namespace"&gt;using&lt;/span&gt;&amp;nbsp;System;&lt;br /&gt; &lt;br /&gt; &lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span class="ReferenceType"&gt;class&lt;/span&gt;&amp;nbsp;SourceType&lt;br /&gt; {&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span class="Modifier"&gt;static&lt;/span&gt;&amp;nbsp;&lt;span class="ValueType"&gt;int&lt;/span&gt;&amp;nbsp;Select(Func&amp;lt;&lt;span class="ReferenceType"&gt;string&lt;/span&gt;,&lt;span class="ReferenceType"&gt;string&lt;/span&gt;&amp;gt;&amp;nbsp;ignored)&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Console.WriteLine(&lt;span class="String"&gt;&amp;quot;Select&amp;nbsp;called!&amp;quot;&lt;/span&gt;);&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Statement"&gt;return&lt;/span&gt;&amp;nbsp;10;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; &lt;span class="ReferenceType"&gt;class&lt;/span&gt;&amp;nbsp;Test&lt;br /&gt; {&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Modifier"&gt;static&lt;/span&gt;&amp;nbsp;&lt;span class="ValueType"&gt;void&lt;/span&gt;&amp;nbsp;Main()&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="ValueType"&gt;int&lt;/span&gt;&amp;nbsp;query&amp;nbsp;=&amp;nbsp;&lt;span class="Linq"&gt;from&lt;/span&gt;&amp;nbsp;x&amp;nbsp;&lt;span class="Statement"&gt;in&lt;/span&gt;&amp;nbsp;SourceType&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Linq"&gt;select&lt;/span&gt;&amp;nbsp;x;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt; } &lt;/div&gt;&lt;/p&gt; &lt;p&gt;That compiles and runs, printing out &lt;code&gt;Select called!&lt;/code&gt;. &lt;code&gt;query&lt;/code&gt; will be 10 after the method has been called.&lt;/p&gt; &lt;p&gt;So, we can call a static method on a type. Anything else? Well, let&amp;#39;s go back to the normal idea of the expression being a value, but this time we&amp;#39;ll change what &lt;code&gt;Select(x =&amp;gt; x)&lt;/code&gt; actually means. There&amp;#39;s no reason it has to be a method call. It &lt;i&gt;looks&lt;/i&gt; like a method call, but then so do delegate invocations...&lt;/p&gt; &lt;h3&gt;Delegates via properties&lt;/h3&gt; &lt;p&gt;Let&amp;#39;s create a &amp;quot;LINQ proxy&amp;quot; which has a property of a suitable delegate type. Again, we&amp;#39;ll only provide &lt;code&gt;Select&lt;/code&gt; but it would be possible to do other types - for instance the &lt;code&gt;Where&lt;/code&gt; property could be typed to return another proxy.&lt;/p&gt; &lt;p&gt;&lt;div class="code"&gt; &lt;span class="Namespace"&gt;using&lt;/span&gt;&amp;nbsp;System;&lt;br /&gt; &lt;span class="Namespace"&gt;using&lt;/span&gt;&amp;nbsp;System.Linq.Expressions;&lt;br /&gt; &lt;br /&gt; &lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span class="ReferenceType"&gt;class&lt;/span&gt;&amp;nbsp;LinqProxy&lt;br /&gt; {&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;nbsp;Func&amp;lt;Expression&amp;lt;Func&amp;lt;&lt;span class="ReferenceType"&gt;string&lt;/span&gt;,&lt;span class="ReferenceType"&gt;string&lt;/span&gt;&amp;gt;&amp;gt;,&lt;span class="ValueType"&gt;int&lt;/span&gt;&amp;gt;&amp;nbsp;Select&amp;nbsp;{&amp;nbsp;get;&amp;nbsp;set;&amp;nbsp;}&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; &lt;span class="ReferenceType"&gt;class&lt;/span&gt;&amp;nbsp;Test&lt;br /&gt; {&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Modifier"&gt;static&lt;/span&gt;&amp;nbsp;&lt;span class="ValueType"&gt;void&lt;/span&gt;&amp;nbsp;Main()&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;LinqProxy&amp;nbsp;proxy&amp;nbsp;=&amp;nbsp;&lt;span class="Keyword"&gt;new&lt;/span&gt;&amp;nbsp;LinqProxy();&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;proxy.Select&amp;nbsp;=&amp;nbsp;exp&amp;nbsp;=&amp;gt;&amp;nbsp;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&amp;nbsp;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Console.WriteLine&amp;nbsp;(&lt;span class="String"&gt;&amp;quot;Select({0})&amp;quot;&lt;/span&gt;,&amp;nbsp;exp);&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Statement"&gt;return&lt;/span&gt;&amp;nbsp;15;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;};&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="ValueType"&gt;int&lt;/span&gt;&amp;nbsp;query&amp;nbsp;=&amp;nbsp;&lt;span class="Linq"&gt;from&lt;/span&gt;&amp;nbsp;x&amp;nbsp;&lt;span class="Statement"&gt;in&lt;/span&gt;&amp;nbsp;proxy&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="Linq"&gt;select&lt;/span&gt;&amp;nbsp;x;&lt;br /&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt; } &lt;/div&gt;&lt;/p&gt; &lt;p&gt;Again, it all compiles and runs fine, with an output of &amp;quot;Select(x =&amp;gt; x)&amp;quot;. If you wanted, you could combine the two above approaches - the &lt;code&gt;SourceType&lt;/code&gt; could have a static delegate property instead of a method. Also this would still work if we used a public field instead of a property.&lt;/p&gt; &lt;h3&gt;What else is available?&lt;/h3&gt; &lt;p&gt;Looking through the list of potential expressions, there are plenty more we can try to abuse: namespaces, method groups, anonymous functions, indexers, and events. I haven&amp;#39;t found any nasty ways of using these yet - if we could have methods or properties directly in namespaces (instead of in types) then we could use &lt;code&gt;from x in SomeNamespace&lt;/code&gt; but until that time, I think sanity is reasonably safe. Of course, if you can find any further examples, please let me know!&lt;/p&gt;  &lt;h3&gt;Why is this useful?&lt;/h3&gt; &lt;p&gt;It&amp;#39;s not. It&amp;#39;s really, really not - at least not in any way I can think of. The &amp;quot;proxy with delegate properties&amp;quot; might just have some weird, twisted use, but I&amp;#39;d have to see it to believe it. Of course, these are useful examples to prove what the compiler&amp;#39;s actually doing, and the extent to which query expressions really are just syntactic sugar (but &lt;i&gt;sooo&lt;/i&gt; sweet) - but that doesn&amp;#39;t mean there&amp;#39;s a good use for the technique in real code.&lt;/p&gt;  &lt;p&gt;Again, if you can find a genuine use for this, please &lt;a href="mailto:skeet@pobox.com"&gt;mail me&lt;/a&gt;. I&amp;#39;d love to hear about such oddities.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1528207" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/LINQ/default.aspx">LINQ</category></item><item><title>Implementing deferred execution, and a potential trap to avoid</title><link>http://msmvps.com/blogs/jon_skeet/archive/2008/02/28/implementing-deferred-execution-and-a-potential-trap-to-avoid.aspx</link><pubDate>Thu, 28 Feb 2008 00:32:18 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1526375</guid><dc:creator>skeet</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/rsscomments.aspx?PostID=1526375</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/commentapi.aspx?PostID=1526375</wfw:comment><comments>http://msmvps.com/blogs/jon_skeet/archive/2008/02/28/implementing-deferred-execution-and-a-potential-trap-to-avoid.aspx#comments</comments><description>&lt;p&gt;When talking about LINQ recently, I doodled an implementation of &lt;code&gt;OrderBy&lt;/code&gt; on a whiteboard. Now, I know the real &lt;code&gt;OrderBy&lt;/code&gt; method has to support &lt;code&gt;ThenBy&lt;/code&gt; which makes life slightly tougher, but let&amp;#39;s suppose for a moment that it didn&amp;#39;t. Let&amp;#39;s further suppose that we don&amp;#39;t mind O(n&lt;sup&gt;2&lt;/sup&gt;) efficiency, but we do want to abide by the restriction that the sort should be stable. Here&amp;#39;s one implementation:&lt;/p&gt; &lt;p&gt; &lt;div class="code"&gt;&lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span class="Modifier"&gt;static&lt;/span&gt; IEnumerable&amp;lt;TSource&amp;gt; OrderBy&amp;lt;TSource,TKey&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; (&lt;span class="Keyword"&gt;this&lt;/span&gt; IEnumerable&amp;lt;TSource&amp;gt; source,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Func&amp;lt;TSource,TKey&amp;gt; keySelector)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; IComparer&amp;lt;TKey&amp;gt; comparer = Comparer&amp;lt;TKey&amp;gt;.Default;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; List&amp;lt;TSource&amp;gt; buffer = &lt;span class="Keyword"&gt;new&lt;/span&gt; List&amp;lt;TSource&amp;gt;();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;foreach&lt;/span&gt; (TSource item &lt;span class="Statement"&gt;in&lt;/span&gt; source)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="InlineComment"&gt;// Find out where to insert the element -&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="InlineComment"&gt;// immediately before the first element that &lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="InlineComment"&gt;// compares as greater than the new one.&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; TKey key = keySelector(item);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="ValueType"&gt;int&lt;/span&gt; index = buffer.FindIndex&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; (x =&amp;gt; comparer.Compare(keySelector(x), key) &amp;gt; 0);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; buffer.Insert(index==-1 ? buffer.Count : index, item);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;return&lt;/span&gt; buffer;&lt;br /&gt;} &lt;/div&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;What&amp;#39;s wrong with it? Well, it compiles, and seems to run okay - but it doesn&amp;#39;t defer execution. As soon as you call the method, it will suck all the data from the source and sort it. &lt;code&gt;List&amp;lt;T&amp;gt;&lt;/code&gt; implements &lt;code&gt;IEnumerable&amp;lt;T&amp;gt;&lt;/code&gt; with no problems, so we&amp;#39;re fine to just return &lt;code&gt;buffer&lt;/code&gt;... but we can very easily make it defer execution. Look at the end of this code (the actual sorting part is the same):&lt;/p&gt; &lt;p&gt; &lt;div class="code"&gt;&lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span class="Modifier"&gt;static&lt;/span&gt; IEnumerable&amp;lt;TSource&amp;gt; OrderBy&amp;lt;TSource,TKey&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; (&lt;span class="Keyword"&gt;this&lt;/span&gt; IEnumerable&amp;lt;TSource&amp;gt; source,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Func&amp;lt;TSource,TKey&amp;gt; keySelector)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; IComparer&amp;lt;TKey&amp;gt; comparer = Comparer&amp;lt;TKey&amp;gt;.Default;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; List&amp;lt;TSource&amp;gt; buffer = &lt;span class="Keyword"&gt;new&lt;/span&gt; List&amp;lt;TSource&amp;gt;();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;foreach&lt;/span&gt; (TSource item &lt;span class="Statement"&gt;in&lt;/span&gt; source)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="InlineComment"&gt;// Find out where to insert the element -&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="InlineComment"&gt;// immediately before the first element that &lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="InlineComment"&gt;// compares as greater than the new one.&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; TKey key = keySelector(item);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="ValueType"&gt;int&lt;/span&gt; index = buffer.FindIndex&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; (x =&amp;gt; comparer.Compare(keySelector(x), key) &amp;gt; 0);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; buffer.Insert(index==-1 ? buffer.Count : index, item);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;foreach&lt;/span&gt; (TSource item &lt;span class="Statement"&gt;in&lt;/span&gt; buffer)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; yield &lt;span class="Statement"&gt;return&lt;/span&gt; item;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;} &lt;/div&gt; &lt;p&gt;It seems odd to be &lt;em&gt;manually&lt;/em&gt; iterating over &lt;code&gt;buffer&lt;/code&gt; instead of just returned it to be iterated over by the client - but suddenly we have deferred execution. None of the above code will run until we actually start asking for data.&lt;/p&gt; &lt;p&gt;The moral of the story? I suspect many developers would change the second form of code into the first, thinking they&amp;#39;re just refactoring - when in fact they&amp;#39;re changing a very significant piece of behaviour. Be careful when implementing iterators!&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1526375" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/LINQ/default.aspx">LINQ</category></item><item><title>Data pipelines as a conceptual stepping stone to higher order functions</title><link>http://msmvps.com/blogs/jon_skeet/archive/2008/02/28/data-pipelines-as-a-conceptual-stepping-stone-to-higher-order-functions.aspx</link><pubDate>Thu, 28 Feb 2008 00:08:40 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1526364</guid><dc:creator>skeet</dc:creator><slash:comments>4</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/rsscomments.aspx?PostID=1526364</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/commentapi.aspx?PostID=1526364</wfw:comment><comments>http://msmvps.com/blogs/jon_skeet/archive/2008/02/28/data-pipelines-as-a-conceptual-stepping-stone-to-higher-order-functions.aspx#comments</comments><description>&lt;p&gt;I was explaining data pipelines in LINQ to Objects to a colleague yesterday, partly as the next step after explaining iterator blocks, and partly because, well, I love talking about C# 3 and LINQ. (Really, it&amp;#39;s becoming a serious problem. Now that I&amp;#39;ve finished writing the main text of my book, my brain is properly processing the stuff I&amp;#39;ve written about. I hadn&amp;#39;t planned to be blogging as actively as I have been recently - it&amp;#39;s just a natural result of thinking about cool things to do with LINQ. It&amp;#39;s great fun, but in some ways I hope it stops soon, because I&amp;#39;m not getting as much sleep as I should.)&lt;/p&gt; &lt;p&gt;When I was describing how methods like &lt;code&gt;Select&lt;/code&gt; take an iterator and return another iterator which, when called, will perform appropriate transformations, something clicked. There&amp;#39;s a conceptual similarity between data pipelines using deferred execution, and higher order functions. There&amp;#39;s a big difference though: I can get my head round data pipelines quite easily, whereas I can only understand higher order functions for minutes at a time, and only if I&amp;#39;ve had a fair amount of coffee. I know I&amp;#39;m not the only one who finds this stuff tricky.&lt;/p&gt; &lt;p&gt;So yes, there&amp;#39;s a disconnect in difficulty level - but I believe that the more comfortable one is with data pipelines, the more feasible it is to think of higher order functions. Writing half the implementation of &lt;a href="http://msmvps.com/blogs/jon.skeet/archive/2008/01/04/quot-push-quot-linq-revisited-next-attempt-at-an-explanation.aspx"&gt;Push LINQ&lt;/a&gt; (thanks go to Marc Gravell for the other half) helped my &amp;quot;gut feel&amp;quot; understanding of LINQ itself significantly, and I believe they helped me cope with currying and the like as well.&lt;/p&gt; &lt;p&gt;I have a sneaking suspicion that if everyone who wanted to &lt;em&gt;use&lt;/em&gt; LINQ had to write their own implementation of LINQ to Objects (or at least a single overload of each significant method) there&amp;#39;d be a much greater depth of understanding. This isn&amp;#39;t a matter of knowing the fiddly bits - it&amp;#39;s a case of grokking just why &lt;code&gt;OrderBy&lt;/code&gt; needs to buffer data, and what deferred execution really means.&lt;/p&gt; &lt;p&gt;(This is moving off the topic slightly, but I really don&amp;#39;t believe it&amp;#39;s inconceivable to suggest that &amp;quot;average&amp;quot; developers implement most of LINQ to Objects themselves. It sounds barmy, but the tricky bit with LINQ to Objects is the design, not the implementation. Suggesting that people implement LINQ to SQL would be a different matter, admittedly. One idea I&amp;#39;ve had for a talk, whether at an MVP open day or a &lt;a href="http://www.developerday.co.uk/ddd/default.asp"&gt;Developer Developer Developer day&lt;/a&gt; is to see how much of LINQ to Objects I could implement in a single talk/lecture slot, explaining the code as I went along. I&amp;#39;d take unit tests but no pre-written implementation. I really think that with an experienced audience who didn&amp;#39;t need too much hand-holding around iterator blocks, extension methods etc to start with, we could do most of it. I&amp;#39;m not saying it would be efficient (thinking particularly of sorting in a stable fashion) but it would be feasible, and I think it would encourage people to think about it more themselves. Any thoughts from any of you? Oh, and yes, I did see the excellent &lt;a href="http://www.microsoft.com/emea/msdn/spotlight/sessionh.aspx?videoid=710"&gt;video of Luke Hoban&lt;/a&gt; doing &lt;code&gt;Select&lt;/code&gt; and &lt;code&gt;Where&lt;/code&gt;. I&amp;#39;d try to cover grouping, joins etc as well.)&lt;/p&gt; &lt;p&gt;I&amp;#39;m hoping that the more experience I have with writing funky little sequence generators/processors, the more natural functional programming with higher order functions will feel. For those of you who are already comfortable with higher order functions, does this sound like a reasonable hope/expectation? Oh, and is the similarity between the two situations anything to do with &lt;a href="http://blogs.msdn.com/wesdyer/archive/2008/01/11/the-marvels-of-monads.aspx"&gt;monads&lt;/a&gt;? I suspect so, but I don&amp;#39;t have a firm enough grasp on monads to say for sure. It&amp;#39;s obviously to do with composition, either way.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1526364" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/LINQ/default.aspx">LINQ</category></item><item><title>Visualising the Mandelbrot set with LINQ - yet again</title><link>http://msmvps.com/blogs/jon_skeet/archive/2008/02/26/visualising-the-mandelbrot-set-with-linq-yet-again.aspx</link><pubDate>Tue, 26 Feb 2008 20:16:28 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1525235</guid><dc:creator>skeet</dc:creator><slash:comments>3</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/rsscomments.aspx?PostID=1525235</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/commentapi.aspx?PostID=1525235</wfw:comment><comments>http://msmvps.com/blogs/jon_skeet/archive/2008/02/26/visualising-the-mandelbrot-set-with-linq-yet-again.aspx#comments</comments><description>&lt;p&gt;I&amp;#39;ve been thinking about ranges again, particularly after &lt;a href="http://csharpindepth.com/ViewNote.aspx?NoteID=48"&gt;catching a book error&lt;/a&gt; just in time, and looking at Marc&amp;#39;s &lt;a href="http://csharpindepth.com/ViewNote.aspx?NoteID=50"&gt;generic complex type&lt;/a&gt;. It struck me that my &lt;a href="http://msmvps.com/blogs/jon.skeet/archive/2007/10/03/linq-to-silliness-generating-a-mandelbrot-with-parallel-potential.aspx"&gt;previous&lt;/a&gt; &lt;a href="http://msmvps.com/blogs/jon.skeet/archive/2007/12/04/a-cautionary-parallel-tale-ordering-isn-t-simple.aspx"&gt;attempts&lt;/a&gt; were all very well, and demonstrated parallelisation quite neatly, but weren&amp;#39;t very LINQy. In particular, they certainly didn&amp;#39;t use LINQ for the tricky part in the same way that &lt;a href="http://blogs.msdn.com/lukeh/archive/2007/04/03/a-ray-tracer-in-c-3-0.aspx"&gt;Luke Hoban&amp;#39;s ray tracer&lt;/a&gt; does.&lt;/p&gt; &lt;p&gt;The thing is, working out the &amp;quot;value&amp;quot; of a particular point in the Mandelbrot set visualisation is actually quite well suited to LINQ:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;Start with a complex value  &lt;li&gt;Apply a transformation to it (square the current value, add the original value from step 1).  &lt;li&gt;Does the result have a modulus &amp;gt; 2? If so, stop.  &lt;li&gt;Have we performed as many iterations as we&amp;#39;re willing to? If so, stop.  &lt;li&gt;Take our new value, and go back to 2.&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;We only need two &amp;quot;extra&amp;quot; bits of code to implement this: a &lt;code&gt;Complex&lt;/code&gt; type, and a way of applying the same transformation repeatedly.&lt;/p&gt; &lt;p&gt;Well, here&amp;#39;s the &lt;code&gt;Complex&lt;/code&gt; type - it contains nothing beyond what we need for this demo, but it&amp;#39;ll do. Obviously Marc&amp;#39;s generic implementation is rather more complete.&lt;/p&gt; &lt;p&gt; &lt;div class="code"&gt;&lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span class="ValueType"&gt;struct&lt;/span&gt; Complex&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Modifier"&gt;readonly&lt;/span&gt;&amp;nbsp;&lt;span class="ValueType"&gt;double&lt;/span&gt; real;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Modifier"&gt;readonly&lt;/span&gt;&amp;nbsp;&lt;span class="ValueType"&gt;double&lt;/span&gt; imaginary;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Modifier"&gt;public&lt;/span&gt; Complex(&lt;span class="ValueType"&gt;double&lt;/span&gt; real, &lt;span class="ValueType"&gt;double&lt;/span&gt; imaginary)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Keyword"&gt;this&lt;/span&gt;.real = real;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Keyword"&gt;this&lt;/span&gt;.imaginary = imaginary;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span class="Modifier"&gt;static&lt;/span&gt; Complex &lt;span class="Keyword"&gt;operator&lt;/span&gt; +(Complex c1, Complex c2)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;return&lt;/span&gt;&amp;nbsp;&lt;span class="Keyword"&gt;new&lt;/span&gt; Complex(c1.real + c2.real, c1.imaginary + c2.imaginary);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span class="Modifier"&gt;static&lt;/span&gt; Complex &lt;span class="Keyword"&gt;operator&lt;/span&gt; *(Complex c1, Complex c2)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;return&lt;/span&gt;&amp;nbsp;&lt;span class="Keyword"&gt;new&lt;/span&gt; Complex(c1.real*c2.real - c1.imaginary*c2.imaginary, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; c1.real*c2.imaginary + c2.real*c1.imaginary);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span class="ValueType"&gt;double&lt;/span&gt; SquareLength&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; get { &lt;span class="Statement"&gt;return&lt;/span&gt; real * real + imaginary * imaginary; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;} &lt;/div&gt; &lt;p&gt;Simple stuff, assuming you know anything about complex numbers.&lt;/p&gt; &lt;p&gt;The other new piece of code is even simpler. It&amp;#39;s just a &lt;em&gt;generator&lt;/em&gt;. It&amp;#39;s a static method which takes an initial value, and a delegate to apply to one value to get the next. It then lazily returns the generated sequece - forever.&lt;/p&gt; &lt;p&gt; &lt;div class="code"&gt;&lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span class="Modifier"&gt;static&lt;/span&gt; IEnumerable&amp;lt;T&amp;gt; Generate&amp;lt;T&amp;gt;(T start, Func&amp;lt;T, T&amp;gt; step)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; T value = start;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;while&lt;/span&gt; (&lt;span class="Keyword"&gt;true&lt;/span&gt;)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; yield &lt;span class="Statement"&gt;return&lt;/span&gt; value;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; value = step(value);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;} &lt;/div&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;Just as an example of use, remember &lt;code&gt;Enumerable.Range&lt;/code&gt; which starts at a particular integer, then adds one repeatedly until it&amp;#39;s yielded as many results as you&amp;#39;ve asked for? Well, here&amp;#39;s a possible implementation, given the &lt;code&gt;Generate&lt;/code&gt; method:&lt;/p&gt; &lt;p&gt; &lt;div class="code"&gt;&lt;span class="Modifier"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span class="Modifier"&gt;static&lt;/span&gt; IEnumerable&amp;lt;&lt;span class="ValueType"&gt;int&lt;/span&gt;&amp;gt; Range(&lt;span class="ValueType"&gt;int&lt;/span&gt; start, &lt;span class="ValueType"&gt;int&lt;/span&gt; count)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;return&lt;/span&gt; Generate(start, x =&amp;gt; x + 1).Take(count);&lt;br /&gt;} &lt;/div&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;These are all the building blocks we require to build our Mandelbrot visualisation. We want a query which will return a sequence of bytes, one per pixel, where each byte represents the colour to use. Anything which goes beyond our maximum number of iterations ends up black (colour 0) and other values will cycle round the colours. I won&amp;#39;t show the drawing code, but the query is now more self-contained:&lt;/p&gt; &lt;p&gt; &lt;div class="code"&gt;&lt;span class="Linq"&gt;var&lt;/span&gt; query = &lt;span class="Linq"&gt;from&lt;/span&gt; row &lt;span class="Statement"&gt;in&lt;/span&gt; Enumerable.Range(0, ImageHeight)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;from&lt;/span&gt; col &lt;span class="Statement"&gt;in&lt;/span&gt; Enumerable.Range(0, ImageWidth)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="InlineComment"&gt;// Work out the initial complex value from the row and column&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;let&lt;/span&gt; c = &lt;span class="Keyword"&gt;new&lt;/span&gt; Complex((col * SampleWidth) / ImageWidth + OffsetX,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; (row * SampleHeight) / ImageHeight + OffsetY)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="InlineComment"&gt;// Work out the number of iterations&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;select&lt;/span&gt; Generate(c, x =&amp;gt; x * x + c).TakeWhile(x =&amp;gt; x.SquareLength &amp;lt; 4)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; .Take(MaxIterations)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; .Count() &lt;span class="Linq"&gt;into&lt;/span&gt; count&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="InlineComment"&gt;// Map that to an appropriate byte value&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;select&lt;/span&gt; (&lt;span class="ValueType"&gt;byte&lt;/span&gt;)(count == MaxIterations ? 0 : (count % 255) + 1); &lt;/div&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;(The various constants used in the expression are defined elsewhere.) This works, and puts the Mandelbrot logic directly into the query. However, I have to admit that it&amp;#39;s &lt;i&gt;much&lt;/i&gt; slower than my earlier versions. Heck, I&amp;#39;m still proud of it though.&lt;/p&gt; &lt;p&gt;As ever, &lt;a href="http://pobox.com/~skeet/csharp/blogfiles/LinqMandelbrot.zip"&gt;full source code is available for download&lt;/a&gt;, should you so wish. &lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1525235" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/Wacky+Ideas/default.aspx">Wacky Ideas</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/LINQ/default.aspx">LINQ</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/Parallelisation/default.aspx">Parallelisation</category></item><item><title>LambdaExpression - source code would be nice</title><link>http://msmvps.com/blogs/jon_skeet/archive/2008/02/21/lambdaexpression-source-code-would-be-nice.aspx</link><pubDate>Thu, 21 Feb 2008 22:19:59 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1521128</guid><dc:creator>skeet</dc:creator><slash:comments>5</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/rsscomments.aspx?PostID=1521128</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/commentapi.aspx?PostID=1521128</wfw:comment><comments>http://msmvps.com/blogs/jon_skeet/archive/2008/02/21/lambdaexpression-source-code-would-be-nice.aspx#comments</comments><description>&lt;p&gt;Just taking a quick break from proof-reading to post a thought I had yesterday. Visual LINQ uses &lt;code&gt;ToString()&lt;/code&gt; to convert an expression tree&amp;#39;s body into readable text. In some cases it works brilliantly, reproducing the original source code exactly - but in other cases it&amp;#39;s far from useful. For instance, from this expression tree representation:&lt;/p&gt; &lt;p&gt; &lt;div class="code"&gt;(Convert(word.get_Chars(0)) = 113) &lt;/div&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;I suspect you wouldn&amp;#39;t have guessed that the original code was:&lt;/p&gt; &lt;p&gt; &lt;div class="code"&gt;word[0] == &amp;#39;q&amp;#39; &lt;/div&gt; &lt;p&gt;Personally I don&amp;#39;t find it terrifically obvious, even though I can see how it works. Here&amp;#39;s a thought though - suppose the &lt;code&gt;LambdaExpression&lt;/code&gt; class had a &lt;code&gt;Source&lt;/code&gt; property which the compiler could optionally provide as a constructor argument, so that you could get at the original source code if you needed it. The use in Visual LINQ is obvious, but would it be useful elsewhere?&lt;/p&gt; &lt;p&gt;Well, suppose that LINQ to SQL couldn&amp;#39;t translate a particular query expression into SQL. Wouldn&amp;#39;t it be nice if it could report the part of the query expression it was having trouble with &lt;i&gt;in the language it was originally written in&lt;/i&gt;? So a VB expression would give source in VB, a C# expression would give source in C# etc.&lt;/p&gt; &lt;p&gt;All of this would have to be optional, and I suspect some people would have intellectual property concerns about their source leaking out (most of which would be silly, due to the logic &lt;i&gt;effectively&lt;/i&gt; being available with a call to &lt;code&gt;ToString()&lt;/code&gt; anyway). I think it would be quite handy in a few situations though.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1521128" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/LINQ/default.aspx">LINQ</category></item><item><title>Visual LINQ: Watch query expressions as they happen!</title><link>http://msmvps.com/blogs/jon_skeet/archive/2008/02/20/visual-linq-watch-query-expressions-as-they-happen.aspx</link><pubDate>Wed, 20 Feb 2008 01:22:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1519623</guid><dc:creator>skeet</dc:creator><slash:comments>18</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/rsscomments.aspx?PostID=1519623</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/commentapi.aspx?PostID=1519623</wfw:comment><comments>http://msmvps.com/blogs/jon_skeet/archive/2008/02/20/visual-linq-watch-query-expressions-as-they-happen.aspx#comments</comments><description>&lt;p&gt;Critical link (in case you can&amp;#39;t find it): &lt;a href="http://pobox.com/%7Eskeet/csharp/blogfiles/visuallinq/VisualLinq.zip"&gt;Source Code Download&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Update: Dmitry Lyalin has put together a &lt;a href="http://www.betterknowaframework.com/screencast/JonSkeet/VisualLinq.aspx"&gt;screencast&lt;/a&gt; of Visual LINQ in action - it gives a much better idea of what it&amp;#39;s like than static pictures do. There&amp;#39;s music, but no speech - so you won&amp;#39;t be missing any important information if you mute it.&amp;nbsp;&lt;/p&gt; &lt;p&gt;I was going to save this until it was rather more polished, but I&amp;#39;ve just started reading the first proofs of C# in Depth, so it&amp;#39;s unlikely I&amp;#39;ll have much time for coding in the near future. I&amp;#39;m too excited about the results of Monday night to keep them until the book&amp;#39;s done :)&lt;/p&gt; &lt;p&gt;After my &lt;a href="http://msmvps.com/blogs/jon.skeet/archive/2008/02/14/human-linq.aspx"&gt;Human LINQ&lt;/a&gt; experiment, I was considering how it my be possible to watch queries occurring on a computer. I had the idea of turning LINQ to Objects into WPF animations... and it just about works. The initial version took about 3 hours on Monday night, and it&amp;#39;s had a few refinements since. It&amp;#39;s very definitely not finished, but I&amp;#39;ll go into that in a minute.&lt;/p&gt; &lt;p&gt;The basic idea is that you write a nearly-normal query expression like this:&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class="code"&gt;VisualSource&amp;lt;&lt;span class="ReferenceType"&gt;string&lt;/span&gt;&amp;gt; words = &lt;span class="Keyword"&gt;new&lt;/span&gt; VisualSource&amp;lt;&lt;span class="ReferenceType"&gt;string&lt;/span&gt;&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; (&lt;span class="Keyword"&gt;new&lt;/span&gt;[] { &lt;span class="String"&gt;&amp;quot;the&amp;quot;&lt;/span&gt;, &lt;span class="String"&gt;&amp;quot;quick&amp;quot;&lt;/span&gt;, &lt;span class="String"&gt;&amp;quot;brown&amp;quot;&lt;/span&gt;, &lt;span class="String"&gt;&amp;quot;fox&amp;quot;&lt;/span&gt;, &lt;span class="String"&gt;&amp;quot;jumped&amp;quot;&lt;/span&gt;, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="String"&gt;&amp;quot;over&amp;quot;&lt;/span&gt;, &lt;span class="String"&gt;&amp;quot;the&amp;quot;&lt;/span&gt;, &lt;span class="String"&gt;&amp;quot;lazy&amp;quot;&lt;/span&gt;, &lt;span class="String"&gt;&amp;quot;dog&amp;quot;&lt;/span&gt; }, &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; canvas, &lt;span class="String"&gt;&amp;quot;words&amp;quot;&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;&lt;span class="Linq"&gt;var&lt;/span&gt; query = &lt;span class="Linq"&gt;from&lt;/span&gt; word &lt;span class="Statement"&gt;in&lt;/span&gt; words&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;where&lt;/span&gt; word.Length &amp;gt; 3&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;select&lt;/span&gt;&amp;nbsp;&lt;span class="Keyword"&gt;new&lt;/span&gt; { Word = word, Length = word.Length};&lt;br /&gt;&lt;br /&gt;pipeline = query.End(); &lt;/div&gt; &lt;p&gt;... and then watch it run. At the moment, the code is embedded in the constructor for MainWindow, but obviously it needs to be part of the UI at some point in the future. To explain the above code a little bit further, the VisualSource class displays a data source on screen, and calling End() on a query creates a data sink which will start fetching data as soon as you hit the relevant &amp;quot;Go!&amp;quot; button in the UI. Speaking of which, here&amp;#39;s what you see when you start it:&lt;/p&gt; &lt;p&gt;&lt;img src="http://pobox.com/%7Eskeet/csharp/blogfiles/visuallinq/VisualLinq_Ready.png" alt="" /&gt; &lt;/p&gt; &lt;p&gt;When you tell it to go, words descend from the source, and hit the &amp;quot;where&amp;quot; clause:&lt;/p&gt; &lt;p&gt;&lt;img src="http://pobox.com/%7Eskeet/csharp/blogfiles/visuallinq/VisualLinq_Predicate.png" alt="" /&gt; &lt;/p&gt; &lt;p&gt;As you can see, &amp;quot;the&amp;quot; doesn&amp;#39;t meet the criterion of &amp;quot;word.Length &amp;gt; 3&amp;quot;, so the answer &amp;quot;False&amp;quot; is fading up. Fast forward a few seconds, and we&amp;#39;ll see the first passing result has reached the bottom, with the next word on its way down:&lt;/p&gt; &lt;p&gt;&lt;img src="http://pobox.com/%7Eskeet/csharp/blogfiles/visuallinq/VisualLinq_SecondWord.png" alt="" /&gt; &lt;/p&gt; &lt;p&gt;Results accumulate at the bottom so you can see what&amp;#39;s going on:&lt;/p&gt; &lt;p&gt;&lt;img src="http://pobox.com/%7Eskeet/csharp/blogfiles/visuallinq/VisualLinq_ResultsBuilding.png" alt="" /&gt; &lt;/p&gt; &lt;p&gt;To be honest, it&amp;#39;s better seen &amp;quot;live&amp;quot; as an animation... but the important thing is that none of the text above is hand-specified (other than the data and the source name). If you change the query and rebuild/run, the diagram will change - so long as I&amp;#39;ve actually implemented the bits you use. So far, you can use:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;select&lt;/li&gt; &lt;li&gt;where&lt;/li&gt; &lt;li&gt;group (with trivial or non-trivial elementSelector)&lt;/li&gt; &lt;li&gt;multiple &amp;quot;from&amp;quot; clauses (invoking SelectMany)&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Select and Where have the most polish applied to them - they&amp;#39;ve got relatively fancy animations. Grouping works, but it appears to be just swallowing data until it spews it all out later - I want to build up what it&amp;#39;s &lt;i&gt;going&lt;/i&gt; to return visually as it&amp;#39;s doing it. SelectMany could be a lot prettier than it is.&lt;/p&gt; &lt;p&gt;So, what&amp;#39;s wrong with it? Well:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Ordering isn&amp;#39;t implemented&lt;/li&gt; &lt;li&gt;Join isn&amp;#39;t implemented&lt;/li&gt; &lt;li&gt;GroupJoin isn&amp;#39;t implemented&lt;/li&gt; &lt;li&gt;The animation could do with tweaking (a lot!)&lt;/li&gt; &lt;li&gt;The code itself is fairly awful&lt;/li&gt; &lt;li&gt;The UI is unpolished (but functional) - my WPF skills are sadly lacking&lt;/li&gt; &lt;li&gt;It would be nice to lay the query out more sensibly (it gets messy with multiple sources for multiple &amp;quot;from&amp;quot; clauses)&lt;/li&gt; &lt;li&gt;Allow the user to enter a query (and their own data sources)&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Despite all of that though, I&amp;#39;m really pleased with it. It uses expression trees to create a textual representation of the logic, then compiles them to delegates for the actual projection etc. A bit of jiggery pokery was needed to make anonymous types look nice, and I dare say there&amp;#39;ll be more of that to come.&lt;/p&gt; &lt;p&gt;Interested yet? The &lt;a href="http://pobox.com/%7Eskeet/csharp/blogfiles/visuallinq/VisualLinq.zip"&gt;source code is available&lt;/a&gt; so you can play with it yourself. Let me know if you plan to make any significant improvements, and we could consider starting a SourceForge project for it.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1519623" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/LINQ/default.aspx">LINQ</category></item><item><title>Human LINQ</title><link>http://msmvps.com/blogs/jon_skeet/archive/2008/02/14/human-linq.aspx</link><pubDate>Thu, 14 Feb 2008 23:49:32 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1514684</guid><dc:creator>skeet</dc:creator><slash:comments>6</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/rsscomments.aspx?PostID=1514684</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/commentapi.aspx?PostID=1514684</wfw:comment><comments>http://msmvps.com/blogs/jon_skeet/archive/2008/02/14/human-linq.aspx#comments</comments><description>&lt;p&gt;Last night I gave a talk about C# 3 and LINQ, organised by &lt;a href="http://iterativetraining.co.uk/"&gt;Iterative Training&lt;/a&gt; and &lt;a href="http://www.nxtgenug.net/"&gt;NxtGenUG&lt;/a&gt;. I attempted to cover all the features of C# 3 and the basics of LINQ in about an hour and a half or so. It&amp;#39;s quite a brutal challenge, and obviously I wasn&amp;#39;t able to go into much detail about anything. It went down reasonably well, but I can&amp;#39;t help feeling there&amp;#39;s a lot of room for improvement. That said, there was one part of the talk which really &lt;em&gt;did&lt;/em&gt; go well, and made the appropriate points effectively.&lt;/p&gt; &lt;p&gt;I had demonstrated the following LINQ query in code:&lt;/p&gt; &lt;p&gt; &lt;div class="code"&gt;&lt;span class="Namespace"&gt;using&lt;/span&gt; System;&lt;br /&gt;&lt;span class="Namespace"&gt;using&lt;/span&gt; System.Linq;&lt;br /&gt;&lt;br /&gt;&lt;span class="ReferenceType"&gt;class&lt;/span&gt; Test&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Modifier"&gt;static&lt;/span&gt;&amp;nbsp;&lt;span class="ValueType"&gt;void&lt;/span&gt; Main(&lt;span class="ReferenceType"&gt;string&lt;/span&gt;[] args)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;var&lt;/span&gt; words = &lt;span class="Keyword"&gt;new&lt;/span&gt;[] {&lt;span class="String"&gt;&amp;quot;the&amp;quot;&lt;/span&gt;, &lt;span class="String"&gt;&amp;quot;quick&amp;quot;&lt;/span&gt;, &lt;span class="String"&gt;&amp;quot;brown&amp;quot;&lt;/span&gt;, &lt;span class="String"&gt;&amp;quot;fox&amp;quot;&lt;/span&gt;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="String"&gt;&amp;quot;jumped&amp;quot;&lt;/span&gt;, &lt;span class="String"&gt;&amp;quot;over&amp;quot;&lt;/span&gt;, &lt;span class="String"&gt;&amp;quot;the&amp;quot;&lt;/span&gt;, &lt;span class="String"&gt;&amp;quot;lazy&amp;quot;&lt;/span&gt;, &lt;span class="String"&gt;&amp;quot;dog&amp;quot;&lt;/span&gt;};&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;var&lt;/span&gt; query = &lt;span class="Linq"&gt;from&lt;/span&gt; x &lt;span class="Statement"&gt;in&lt;/span&gt; words&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;where&lt;/span&gt; x.Length &amp;gt; 3&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;where&lt;/span&gt; x[0] != &amp;#39;q&amp;#39;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;select&lt;/span&gt; x.ToUpper();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Statement"&gt;foreach&lt;/span&gt; (&lt;span class="ReferenceType"&gt;string&lt;/span&gt; word &lt;span class="Statement"&gt;in&lt;/span&gt; query)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Console.WriteLine(word);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;} &lt;/div&gt; &lt;p&gt;I know it would have been easy to combine the two &amp;quot;where&amp;quot; clauses, but separating them helped with the second part of the demonstration.&lt;/p&gt; &lt;p&gt;In the pizza break, I had prepared sheets of paper - some with the words on (&amp;quot;the&amp;quot;, &amp;quot;quick&amp;quot; etc), and some with clauses (&amp;quot;from x in words&amp;quot;, &amp;quot;where x.Length &amp;gt; 3&amp;quot; etc). I asked for 5 volunteers, who I arranged in a line, facing the rest of the audience. I stood at &amp;quot;audience left&amp;quot; with the sheets of words, gave the next person the &amp;quot;from&amp;quot; clause, then the first &amp;quot;where&amp;quot; clause etc. The person at the far end didn&amp;#39;t have a sheet of paper, but they were acting as the foreach loop.&lt;/p&gt; &lt;p&gt;I suspect you can see what&amp;#39;s coming - we ran possibly the slowest LINQ query in the world. However, we did it reasonably accurately: when the next piece of information was needed, a person would turn to their neighbour and request it; the request would pass up the line until it got to me, whereupon I&amp;#39;d hand over a sheet of paper with a word on. If a &amp;quot;where&amp;quot; clause filtered out a word, they just dropped the piece of paper. When a word reached the far end, the guy shouted it out.&lt;/p&gt; &lt;p&gt;With this, I was able to illustrate:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Deferred execution (nothing starts happening until the foreach loop executes)&lt;/li&gt; &lt;li&gt;Streaming (only a single word was ever on the move at once)&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Next we added an &amp;quot;orderby&amp;quot; clause in just before the end. Sure enough, we then see buffering in action - the guy representing the ordering can&amp;#39;t return any data to the &amp;quot;select&amp;quot; clause until he&amp;#39;s actually &lt;em&gt;got&lt;/em&gt; all the data.&lt;/p&gt; &lt;p&gt;Finally, we removed the &amp;quot;orderby&amp;quot; clause again, but added a call to Count(). We didn&amp;#39;t have time to go into a lot of detail, but I &lt;em&gt;think&lt;/em&gt; people understood why that led to immediate execution rather than the deferred execution we had earlier.&lt;/p&gt; &lt;p&gt;I suspect I&amp;#39;m not the first person to do something like this, but I&amp;#39;m still really pleased with it. If you&amp;#39;re ever talking about LINQ and people&amp;#39;s eyes are glazing over, it&amp;#39;s a fun little demo. It wasn&amp;#39;t perfect though; there are things I&amp;#39;d change:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Put the upper case version of the word on the back of the paper. We had to imagine the result of the projection.&lt;/li&gt; &lt;li&gt;Having two &amp;quot;where&amp;quot; clauses is useful for the first demo, but slows things down after that.&lt;/li&gt; &lt;li&gt;Possibly use fewer words - it takes quite a while, and having been through it three times, the audience may grow impatient.&lt;/li&gt; &lt;li&gt;Explain deferred execution more in terms of the result type - it&amp;#39;ll make it easier to contrast with immediate execution&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Overall, it was a really fun night. I did a little interview with Dave McMahon afterwards, which should go up on the &lt;a href="http://www.nxtgenug.net"&gt;NxtGenUG&lt;/a&gt; site at some point. I suspect I was talking rather too quickly for the whole time, but we&amp;#39;ll see how it pans out.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1514684" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/LINQ/default.aspx">LINQ</category></item><item><title>Extension methods on lamdba expressions don't work, unfortunately</title><link>http://msmvps.com/blogs/jon_skeet/archive/2008/01/08/extension-methods-on-lamdba-expressions-don-t-work-unfortunately.aspx</link><pubDate>Tue, 08 Jan 2008 23:37:30 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1448818</guid><dc:creator>skeet</dc:creator><slash:comments>3</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/rsscomments.aspx?PostID=1448818</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/commentapi.aspx?PostID=1448818</wfw:comment><comments>http://msmvps.com/blogs/jon_skeet/archive/2008/01/08/extension-methods-on-lamdba-expressions-don-t-work-unfortunately.aspx#comments</comments><description>&lt;p&gt;Over the Christmas holidays, I thought I&amp;#39;d experiment with something I&amp;#39;d been thinking about a little - sorting a generic &lt;code&gt;IList&amp;lt;T&amp;gt;&lt;/code&gt;. Now, before anyone gets huffy, I&amp;#39;m well aware of &lt;code&gt;OrderBy&lt;/code&gt; in LINQ to Objects. However, sometimes you want to sort collections in-place, and as &lt;code&gt;IList&amp;lt;T&amp;gt;&lt;/code&gt; provides random access, there&amp;#39;s no reason we shouldn&amp;#39;t be able to. Now, I &lt;em&gt;do&lt;/em&gt; like the way that OrderBy allows multiple criteria to be specified, whether they should be applied in an ascending or descending fashion, and by way of just &amp;quot;compare by this projection&amp;quot; rather than having to actually implement the comparison yourself. I thought I could probably make use of those ideas again. &lt;/p&gt; &lt;p&gt;Unlike in LINQ to Objects, the sort would occur immediately, which means I couldn&amp;#39;t use quite the chained syntax of &lt;code&gt;OrderBy(...).ThenBy(...).ThenByDescending(...)&lt;/code&gt; but my plan was to allow code like this:&lt;/p&gt; &lt;p&gt; &lt;div class="code"&gt;List&amp;lt;Person&amp;gt; myList = ...;&lt;br /&gt;&lt;br /&gt;myList.SortBy((person =&amp;gt; person.Name).Ascending(),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; (person =&amp;gt; person.DateOfBirth).Descending(),&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; (person =&amp;gt; person.SocialSecurityNumber).Ascending()); &lt;/div&gt; &lt;p&gt;Because each of the different output types involved might be different, that would only work for as many overloads as I&amp;#39;d implement. An alternative would be:&lt;/p&gt; &lt;p&gt; &lt;div class="code"&gt;Comparer&amp;lt;Person&amp;gt; sorter = Comparer.By(person =&amp;gt; person.Name)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; .ThenByDescending(person =&amp;gt; person.DateOfBirth)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; .ThenBy(person =&amp;gt; person.SocialSecurityNumber);&lt;br /&gt;&lt;br /&gt;sorter.Sort(myList); &lt;/div&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;I did like the idea of the &lt;code&gt;Ascending&lt;/code&gt; and &lt;code&gt;Descending&lt;/code&gt; extension methods though, operating on &lt;code&gt;Func&amp;lt;T1,T2&amp;gt;&lt;/code&gt;. Unfortunately, the dot operator doesn&amp;#39;t work on lambda expressions, even though the expression itself is implicitly convertible to &lt;code&gt;Func&amp;lt;T1,T2&amp;gt;&lt;/code&gt;. &lt;/p&gt; &lt;p&gt;My plan isn&amp;#39;t entirely scuppered - the latter syntax will still work, and there are probably some alternatives I can work out. I think there are nice possibilities around extension methods and delegates though, and it&amp;#39;s a shame they&amp;#39;re not useful for lambda expressions. Ah well.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1448818" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/LINQ/default.aspx">LINQ</category></item><item><title>LINQ to Objects - not just for in-memory collections</title><link>http://msmvps.com/blogs/jon_skeet/archive/2008/01/08/linq-to-objects-not-just-for-in-memory-collections.aspx</link><pubDate>Tue, 08 Jan 2008 23:21:41 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1448804</guid><dc:creator>skeet</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/rsscomments.aspx?PostID=1448804</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/commentapi.aspx?PostID=1448804</wfw:comment><comments>http://msmvps.com/blogs/jon_skeet/archive/2008/01/08/linq-to-objects-not-just-for-in-memory-collections.aspx#comments</comments><description>&lt;p&gt;I&amp;#39;ve just seen LINQ to Objects described as the LINQ provider for &amp;quot;in-memory collections&amp;quot; again. It&amp;#39;s a fairly frequent occurrence, and I may have done it myself on occasion. It doesn&amp;#39;t do LINQ to Objects justice. An example I&amp;#39;ve used in a few places is a query which runs over log files. Something along the lines of:&lt;/p&gt; &lt;p&gt; &lt;div class="code"&gt;&lt;span class="Linq"&gt;var&lt;/span&gt; query = &lt;span class="Linq"&gt;from&lt;/span&gt; file &lt;span class="Statement"&gt;in&lt;/span&gt; Directory.GetFiles(@&lt;span class="String"&gt;&amp;quot;c:\logs&amp;quot;&lt;/span&gt;, &lt;span class="String"&gt;&amp;quot;*.log&amp;quot;&lt;/span&gt;)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;from&lt;/span&gt; line &lt;span class="Statement"&gt;in&lt;/span&gt;&amp;nbsp;&lt;span class="Keyword"&gt;new&lt;/span&gt; LineReader(file)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;let&lt;/span&gt; entry = &lt;span class="Keyword"&gt;new&lt;/span&gt; LogEntry(line)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;where&lt;/span&gt; entry.Severity = Severity.Critical&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span class="Linq"&gt;select&lt;/span&gt; entry; &lt;/div&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;Where&amp;#39;s the in-memory collection here? I suppose there&amp;#39;s the array of log file names, but that&amp;#39;s about it. LINQ to Objects isn&amp;#39;t restricted to datasets which fit comfortably in memory. The above query could process many gigs of data very easily, limited basically by disk speed (and date/time parsing speed in my experience, but that&amp;#39;s a topic for another post).&lt;/p&gt; &lt;p&gt;What LINQ to Objects does is &lt;em&gt;in-process querying of enumerable sequences of data&lt;/em&gt;. More of a mouthful than &amp;quot;querying in-memory collections&amp;quot; but more accurate, IMO.&lt;/p&gt; &lt;p&gt;Rant over. Well, for a couple of minutes.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1448804" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/LINQ/default.aspx">LINQ</category></item></channel></rss>