tags:

views:

346

answers:

3

Hi Everyone,

Are the following Lambda and Linq expressions equivalent in terms of execution paths? I guess I'm wondering if the Linq is going to run differently because it's going to create an IEnumerable before determining if the enumeration has anything in it whereas the lambda expression will stop on the first digit it finds.

var x = valueToMatch
    .Any(c => Char.IsDigit(c));

var y = (from c in valueToMatch
         select c).Any(c => Char.IsDigit(c)); here

Thx! Joel

+1  A: 

They are roughly equivalent. The compiler will probably optimize out the select and the two will be 100% identical. At anyrate, Linq is lazy-evaluated so valueToMatch will be enumerated exactly the same amount in both cases.

Talljoe
The compiler will NOT optimize out the select, and there is a good reason for that. See my article on the subject: http://blogs.msdn.com/ericlippert/archive/2008/05/12/trivial-projections-are-usually-optimized-away.aspx
Eric Lippert
+3  A: 

It will run differently, but not in any considerable way. If you use the MSIL Disassembler you will see a slightly different output for the first expression and the second, even with optimizations turned on. You can also look at it using a Reflector (which is a little easier to read).

The second version will basically pass each element through something like:

[CompilerGenerated]
private static char <Match2>b__2(char c)
{
    return c;
}

before it executes the Any(c => Char.IsDigit(c)) expression. So there is indeed a difference.

however, the difference is very small in my opinion. Testing a list of 10,000 characters being looped over 10,000,000 with each method the first one clocks in around ~125ms while the second method takes ~185ms.

rmoore
you can also use LINQPad to see the IL.IMHO the "from c in valueToMatch select c" is pretty redundant in this case
dplante
Indeed, I think it was more of a 'what happens' thought exercise, at least for me.
rmoore
A: 

For query expressions, this represents the identity function:

from c in valueToMatch select c

This means the expression's result will be exactly equal to the input, matchToValue. Therefore, the examples you have provided are semantically equivalent.

In the case of a non-identity selection such as:

from c in valueToMatch select c + ";"

an IEnumerable<char> is created which, when enumerated, will consume the contents of valueToMatch and alter them.

This call:

(from c in valueToMatch select c + ";").Any(c => Char.IsDigit(c))

enumerates the inner query until it finds a match. As you can see, no matter the source query, it will not run until the call to Any. The IEnumerable<char> instance represents the ability to run a query, not a query that's already been run. This concept is known as deferred execution.

Bryan Watts