0

(Edit after closing: the duplicate is not a duplicate of my question, but I found my answers within an explanation of lazy evaluation.)

Original question:

Disclaimers:

  • this is my 1st question here,
  • I'm neither a Linq nor a database professional,
  • I cannot use Visual Studio at the moment to compile/test any code.

I have puzzles but not the big picture of how Linq works, yet:

This last 2 point makes me conclude Linq(-to-Objects) as oppose to databases, does not have predefined execution order for clauses and other query optimizations. (In case there is any difference I'm interested in query syntax as well but I'll only provide examples with functional syntax.)

So, when I write my Linq code like this:

var firstManagerToFire = firedEmployees.Where(x => x.HaveNotBeenFired)
                                       .OfType<Manager>()
                                       .SkipWhile(x => x.Reputation > 0)
                                       .FirstOrDefault();

Was OfType and SkipWhile executed?

And what if I reverse the logic:

var FirstManagerToFire = firedEmployees.OfType<Manager>()
                                       .SkipWhile(x => x.Reputation > 0)
                                       .Where(x => x.HaveNotBeenFired)
                                       .FirstOrDefault();

Was OfType and SkipWhile executed?

If yes, then does Where (the 2nd) executes in the following example:

var managersToFire = firedEmployees.OfType<Manager>()
                                   .Except(firedEmployees.Where(x => !x.HaveNotBeenFired))
                                   .Where(x => x.HaveNotBeenFired)
                                   .ToArray();

Does it matter (in terms of executing Where) if I force an immediate execution within Except (in this or in any other case)?

                                   .Except(firedEmployees.Where(x => !x.HaveNotBeenFired).ToList())

I can imagine this brings enough detail for the JIT(?) to not execute Where.

Edit:

Thanks for all the useful comments! If they are all executed, how? Is it like:

public static IEnumerable<TResult> OfType<TSource, TResult>(this TSource source)
{
    foreach (var item in source)
        #region unreached area when empty
        if (item is TResult)
            yield return item as TResult;
        #endregion
}
public static IEnumerable<TSource> Where<TSource>(this TSource source, Func<TSource, bool> MatchesFilter)
{
    foreach (var item in source)
        #region unreached area when empty
        if (MatchesFilter(item))
            yield return item;
        #endregion
}
Alb
  • 412
  • 5
  • 12
  • 4
    *"makes me conclude Linq(-to-Objects) ... does not have predefined execution order"* - **not true**. `Include` is specific to LINQ to EF and only adds metadata to the query. It doesn't evaluate anything. The metadata tells the query to include those entities in the returned graph. In LINQ to Objects, the chain is executed in the exact order specified. – madreflection Feb 17 '20 at 23:55
  • 1
    Your second code snippet ("what if I reverse the logic") will not compile, as `Select` will return `IEnumerable`, and `bool` does not have a property called `HaveNotBeenFired`. – yaakov Feb 17 '20 at 23:59
  • @yaakov That's true! I will edit. – Alb Feb 18 '20 at 00:00
  • 2
    @Jawad that is incorrect, if LINQ's `Where` produces 0 results it returns an Enumerable with 0 items, not a null. – Washington A. Ramos Feb 18 '20 at 00:02
  • 2
    @Alb - With `IEnumerable` all operators are executed - regardless if a `Where` returns zero items. With `IQueryable` none of the operators are executed - it is all translated to SQL (or other external language) and that is executed. – Enigmativity Feb 18 '20 at 00:27
  • @Enigmativity Depending - in LINQ to EF Core 2.x, an automatic switch to client evaluation can occur in the middle of a chain, and in LINQ to EF Core 3.x, the final `Select` can be client executed. – NetMage Feb 18 '20 at 00:37
  • @NetMage - Yes, but isn't that at the point that the `IQueryable` turns into an `IEnumerable`? Or are there some smarts that determines what parts are executed on the DB versus memory? – Enigmativity Feb 18 '20 at 01:15
  • _"If they are all executed, how?"_ -- As noted [above](https://stackoverflow.com/questions/60271943/does-any-linq-operator-executes-after-where-yields-no-element?noredirect=1#comment106612492_60271943), all of the methods (operators) are executed. Each method called instantiates a new query result that will, when the full query ultimately is resolved, pull from the query (enumerable) passed to it, and produce a new query result (enumerable). See marked duplicate and many other related Q&A for more details. – Peter Duniho Feb 18 '20 at 01:33
  • 1
    See also https://stackoverflow.com/questions/2515796/deferred-execution-and-eager-evaluation – Peter Duniho Feb 18 '20 at 01:34
  • @Enigmativity No, it remains an `IQueryable` all the way through. – NetMage Feb 18 '20 at 01:42
  • @PeterDuniho Thanks to comment not just close! I've read your 2nd link of [lazy and eager evaluation](https://stackoverflow.com/questions/2515796/deferred-execution-and-eager-evaluation) which - along with your briefing - answers my question (the overall flow)! :) **I would rather change the marked duplicate to that.** – Alb Feb 18 '20 at 01:53
  • Changing `.SkipWhile(x => x.Reputation > 0)` to use a [statement lambda](https://learn.microsoft.com/dotnet/csharp/programming-guide/statements-expressions-operators/lambda-expressions#statement-lambdas) such as `.SkipWhile(x => { Console.WriteLine($"SkipWhile({x})"); return x.Reputation > 0; })` would be a quick way to test if it is executed or not. – Lance U. Matthews Feb 18 '20 at 02:29
  • Yes, true. If I'd have Visual Studio I'd started the question as now the edit looks. – Alb Feb 18 '20 at 02:43
  • 1
    If you want to know what `Where` and `OfType` and so on do, just read the source code. I note that there are optimizations for `Where` and `Select` that are a little tricky to understand but you'll figure it out. – Eric Lippert Feb 18 '20 at 02:54
  • Visual Studio and VSCode are both free and available on both PC and Mac; maybe you should get them and debug through the code if you're interested in what it does. – Eric Lippert Feb 18 '20 at 02:56
  • @EricLippert Thanks. Maybe once I'll read it through. I work full time with VS pro I just don't have them with me right now. :) I found my answer with *lazy evaluation* and *iteration chain* explained. – Alb Feb 18 '20 at 03:02
  • 1
    _"I work full time with VS pro I just don't have them with me right now"_ -- for future reference: Stack Overflow is not an appropriate place for questions of the type "I could find this out later, when I get a chance, but I'm curious right now". Among other reasons, if you can reasonably expect that you'd be able to answer the question yourself in the near future, it is likely that the question would be considered a poor choice to post here. – Peter Duniho Feb 18 '20 at 06:57

0 Answers0